Dossier n°8
Les CheckSums et les CRC
Il faut bien distinguer les checksum, des CRC.
Le premier va additioner le poids des bits qui composent le programme, et vérifier que la somme obtenue est bien égale à une valeur qu'il aura conservé quelque part en mémoire (et souvent HardCoded). Suivant les cas, il peut y avoir moyen de "réctifier" le décallage que pourrait avoir provoqué vos modifications en rééquilibrant la somme des octets à un autre endroit. Vous pouvez aussi trouver la routine de calcul et mettre la main sur la valeur d'origine du checksum (éventuellement modifiable par un hexéditeur) ainsi que sur la nouvelle somme qu'aura votre programme après le patchage. Une dernière solution, et de shunter le blocage lié au checksum au niveau du message "File Corrupted".
Pour les Code de Redondance Cyclique , l'idée principale est de voir le fichier comme une grande série de bits divisées par un nombre, et qui vous laissera un Reste, le CRC! Utilisant un algorythme de calcul, le CRC est beaucoup plus délicat à contourner...
Dans ce dossier, vous trouverez trois parties:
Les Checksums |
Les CRC |
Les programmes |
Ce dossier a été créé à partir d'une compilation de textes du Groupe de Travail, et d'extraits de sites
CheckSum: Généralités
Cheksum: petite saloperie qui calcule le poids des octets composant les codes du programme.
Par exemple 5F en hexadécimal pèsera 95, et 5E pèsera 94. Donc si vous utilisez un éditeur
héxa pour modifier l'exécutable, vous obtiendrez une boite "Intégrity Check Violation
error" dès le lancement de celui-ci. Ceci dans le meilleur des cas, et dans le pire, le programme se
contentera de cloturer l'application.
Comment cibler la routine de détection d'un Checksum corrompu
Certains programmes vérifient leur intégrité au démarrage
et refusent de se lancer s'ils ont été "corrompus". Souvent cette protection est facile
à retirer : bpx MessageBoxA si le soft affiche une messagebox pour signaler le problème ou tout simplement
en traçant et en repérant le branchement qui fait quitter le programme. Néanmoins, il peut
arriver que cette vérif soit bien faite et bien intégrée dans le programme (vérifs
multiples et fonction de hachage pas évidente à repérer). C'est le cas des récentes
versions de Windows Commander par exemple. Je me permets donc de vous fournir cette petite astuce : Il y a deux
types de vérifs : celle qui vérifie l'intégrité en mémoire et celle qui vérifie
l'intégrité du fichier exécutable. C'est pour cette dernière que l'astuce est utilisable
: - Repérer dans le soft où celui-ci ouvre le fichier exécutable (bpx CreateFileA le permet
très facilement). - Modifier le soft pour que celui-ci ouvre un autre fichier à la place (original.bak
par exemple). - Et évidemment faite une copie du fichier exécutable non modifié (nommé
original.bak dans l'exemple). Maintenant, le soft peut faire toutes les vérifs d'intégrité
possible, aussi complexe soit-elle, vous ne serez plus embêté...
Remarque : cette astuce à l'avantage
d'être applicable par un patch, puisqu'il suffit juste de copier l'original avant d'appliquer les modifications
sur le fichier exécutable d'origine.
Brénuche
Rectification d'un Checksum par équilibrage
des octets:
Le programme calculant la somme des octets le composant, toutes modifications de cette somme entrainera l'apprition d'un message d'erreur. L'idée consiste à trouver un endroit du programme non utilisé (routines shareware, messages d'erreur...) et d'y soustraire ou additionner à un octet l'equivalent de la différence que vous avez infliger à la cible en la patchant.
Généralités: HelpBldr by Christal
Extrait de Millénium by ACiD BuRN CheckSum Imaginez que vous venez de cracker un messagebox en memoire ou autres merdes et que après avoir modifiè le programme en hexa , le fichier ne se lance plus de tout , mais quitte directe !! ou encore qu'il vous dise: "CRC ERROR blablablaa" Et la vous dites!! merde!!!!! c quoi ce bordel! je peux meme pas patcher ;( alors soit vous utilisez un mem patcher (patch qui ne patch qu'en memoire donc le programme est tjs intacte, mais a besoin d'être lancé avec ca) sois vous reflechissez :) Ca peut très bien etre plusieurs choses en fait !! on va commencer par le checksum ! c quoi ? en fait , le programme fait une somme des valeurs ascii du programme et les compare a une constante par exemple! Et tant que c'est egale a cette constante, le programme se lance sans broncher! Mais vous , vous venez de patcher avec des NOP , je , JMP ou autres !! et ces instructions n'ont pas le même poids ! exemple à 2 francs: il y avait un: JE XXXXXXXXXX et vous l'avez remplacé par un JNE (BEURK , mais ca sera plus simple pour kicker le checksum). on dira que ca ressemblait à ca en hexa: 7428 (pour le "je") == 74h + 28h = 9Ch = 156 donc 156 en decimal !! et vous avez patché en JNE: 7528 (pour le "jne") == 75h + 28 h = 9Dh = 157 157 est different de 156 donc en additionant tous les octets un a un , le programme trouvera une difference et ne se lancera PAS :) comment contourner ca ? Ben , moi je modifierais ca en : 7527 = 75h + 27h = 9Ch = 156 on s'en fout de la valeur apres le jne car il ne sautera pas!! |
Même motif, même punition:
JPEG optimizer 3.5 by D.LiriUm TrEs MinCe et Christal Le Checksum 017F:004290C3 2BF9 SUB EDI,ECX 017F:004290C5 8DB5BCFEFFFF LEA ESI,[EBP-0144] 017F:004290CB 87F7 XCHG ESI,EDI 017F:004290CD 8BD1 MOV EDX,ECX va devenir: 017F:004290C3 2BF9 SUB EDI,ECX 017F:004290C5 8DB00CFEFFFF LEA ESI,[EAX-01F4] 017F:004290CB 87F7 XCHG ESI,EDI 017F:004290CD 8BD1 MOV EDX,ECX |
Rectification d'un Checksum par modification
de sa somme:
Dans ce premier exemple, vous verrez un contrôle de l'intégrité du header, puis comment mettre la main sur la routine de contrôle, et enfin comment obtenir la valeur du checksum d'origine, et la nouvelle valeur liée aux bidouillages infligés à la cible.
DCeSS & PEShield by Pulsar et ChristalCh
|
Danc cet exemple, vous aurez deux cas de figure: Commen forcer le programme à reconnaître le nouveau checksum, et comment modifier le programme en fonction de ce nouveau checksum:
Teleport pro 1.29 by Christal This program has been altered, possibly by a virus; program execution will stop now On a un petit Checksum sur le programme... :0040B482 mov eax, dword ptr [0047B6EC] -> EAX = good value :0040B487 cmp esi, dword ptr [eax] -> ESI = Value réelle calculée :0040B489 je 0040B49E -> bad boy, don't touch my program :0040B48B push ebx :0040B48C push ebx * Possible StringData Ref from Data 0bj ->"This
program has been altered, " qu'il est facile de shunter en faisant un :0040B482 MOV ESI,[0047B6EC] -> good value in ESI :0040B488 NOP :0040B489 JMP 0040B49E -> et on saute le message Pas Glop ! Mais il y a une manière plus élégante de se débarrasser du Checksum : :0040B482 mov eax, dword ptr [0047B6EC] -> EAX = good value :0040B487 cmp esi, dword ptr [eax] -> ESI = Value réelle calculée La bonne valeur du Checksum est placée dans [0047B6EC]. Une rapide recherche dans le Dead Listing semble montrer qu'il n'y aurait pas de mov [0047B6EC], et que par conséquent il est fort probable que la valeur attendue se trouve dans les codes du programme en clair. Une interrogation D *EAX va donner E01928E3, valeur que l'on va retrouver facilement avec un éditeur hexa : 0007B6EC F0B6 4700 E019 28E3 F0B6 0700 0000 0000 5468 6973 ..G... .........This 0007B700 2070 726F 6772 616D 2068 6173 2062 6565 6E20 616C program has been al Et placée juste avant le message d'erreur... |
Détourner la routine "File
Corrupted":
Un checksum n'infecte pas obligatoirement la totalité des codes de l'exécutable. Parfois seul le header de celui ci est contrôlé. Quand le programme à la gentillesse de vous alerter qu'il se juge contaminé par un quelconque Virus (ou toute autre modification), il s'empresse de vous en prévenir. Suivant les cas un BPX sur MessageBoxA peut faire l'affaire, sinon, il faudra tracer le programme dès son EntryPoint.
Shunter la routine en placant un RET au début de celle ci:
Extrait 3D exploration 1.2.54 (ASPack 2000) by Christal En avançant pas à pas, (infirmière, passez-moi F10) :
Ouch ! Le prog à un CRC. :BFF70000 4D 5A 90 00 03 00 00 00-04 00 00 00 FF FF 00 00 MZ.............. :BFF70010 B8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00 ........@....... :BFF70020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ :BFF70030 00 00 00 00 00 00 00 00-00 00 00 00 80 00 00 00 ................ :BFF70040 0E 1F BA 0E 00 B4 09 CD-21 B8 01 4C CD 21 54 68 ........!..L.!Th :BFF70050 69 73 20 70 72 6F 67 72-61 6D 20 63 61 6E 6E 6F is program canno :BFF70060 74 20 62 65 20 72 75 6E-20 69 6E 20 44 4F 53 20 t be run in DOS :BFF70070 6D 6F 64 65 2E 0D 0D 0A-24 00 00 00 00 00 00 00 mode....$....... L'infection part de l'entête du Header (l'adresse 00400000 du programme dont
le contenu a été chargé en BFF70000) :BFF701A0 2E 74 65 78 74 00 00 00-05 C9 04 00 00 90 00 00 .text........... :BFF701B0 00 D0 04 00 00 90 00 00-00 00 00 00 00 00 00 00 ................ :BFF701C0 00 00 00 00 20 00 00 60-5F 49 4E 49 54 00 00 00 .... ..`_INIT... :BFF701C0 00 00 00 00 20 00 00 60-5F 49 4E 49 54 00 00 00 .... ..`_INIT... Histoire de voir si le CRC a infecté l'ensemble des tissus, une petite modification
dans les codes du programme (une version "saine"), va démontrer que seul le header est atteint. :004E5B9E 56 69 72 74 75 61 6C 46-72 65 65 00 56 69 72 74 VirtualFree.Virt :004E5BAE 75 61 6C 50 72 6F 74 65-63 74 00 45 78 69 74 50 ualProtect.ExitP :004E5BBE 72 6F 63 65 73 73 00 00-00 00 00 75 73 65 72 33 rocess.....user3 :004E5BCE 32 2E 64 6C 6C 00 4D 65-73 73 61 67 65 42 6F 78 2.dll.MessageBox :004E5BDE 41 00 77 73 70 72 69 6E-74 66 41 00 4C 4F 41 44 A.wsprintfA.LOAD :004E5BEE 45 52 20 45 52 52 4F 52-00 54 68 65 20 70 72 6F ER ERROR.The pro :004E5BFE 63 65 64 75 72 65 20 65-6E 74 72 79 20 70 6F 69 cedure entry poi :004E5C0E 6E 74 20 25 73 20 63 6F-75 6C 64 20 6E 6F 74 20 nt %s could not Gasp ! :004E54DF 6801F0BF00 PUSH 00BFF001 :004E54E4 C3 RET Et là, brusque changement. :00BFF5C5 61 POPAD :00BFF5C6 7508 JNZ 00BFF5D0 :00BFF5C8 B801000000 MOV EAX,00000001 :00BFF5CD C20C00 RET 000C :00BFF5D0 680814BF00 PUSH 00BF1408 :00BFF5D5 C3 RET En cherchant un peu à partir de cette adresse, le call MessageBoxA/ExitProcess est en : :00BF06B5 E816F9FFFF CALL 00BEFFD0 > cochonnerie here ! :00BF06BA 8B45F8 MOV EAX,[EBP-08] :00BF06BD E85A22FFFF CALL 00BE291C0 Petite ablation discrète, on place un RET à l'entrée du call
en question. |
Shunter la routine en inversant un saut conditionnel:
Genius 2.7 (ASPack) by Christal Le Checksum : Au lancement de votre copie décompressée, le programme va immédiatement détecter qu’il y a un peu plus d’octets que dans la version d’origine. La " punition " est infligé par une boite de message " The
file has been modified ". Eh oui ! :00559DA4 E80F37F0FF call 0045D4B8 :00559DA9 8BD8 mov ebx, eax :00559DAB 8BC6 mov eax, esi :00559DAD E8DE91EAFF call 00402F90 :00559DB2 84DB test bl , bl :00559DB4 7511 jne 00559DC7 Et le voilà ! C'est le premier qui se présente, et qui évite
la procédure du NagScreen. |
Le même, le pareil:
Sales Agent by christal
* Possible StringData Ref from Data Obj ->"^^L;dIZ8" :0040AB7E E86D980000 call 004143F0 :0040AB83 83C408 add esp, 00000008 :0040AB86 83F801 cmp eax, 00000001 :0040AB89 7458 je 0040ABE3 > no jump :0040AB8B 6869010000 push 00000169 :0040AB90 E8BB9B0000 call 00414750 :0040AB95 83C404 add esp, 00000004 :0040AB98 6810200000 push 00002010 :0040AB9D 6A00 push 00000000 :0040AB9F 68A4584500 push 004558A4 :0040ABA4 6A00 push 00000000 :0040ABA6 FF1598224300 Call USER32.MessageBoxA >nag |
ZVolume 3.1 (ASProtect) by LutiN NoIR Je m'attendais à trouver un antisoftice comme dans d'autres progs protégés
avec asprotect mais là on dirait bien que l'on a droit à un cheksum. Pour en être certain je
suis aller sur le site d'asprotect et voilà ce qu'il disent : :0049C2BB 5E POP ESI :0049C2BC 5B POP EBX :0049C2BD C3 RET :0049F9E0 894304 MOV [EBX+04],EAX :0049F9E3 837B0400 CMP DWORD PTR [EBX+04],00 :0049F9E7 7D23 JGE 0049FA0C (JUMP ) :0049FA0C 807DFF00 CMP BYTE PTR [EBP-01],00 :0049FA10 740A JZ 0049FA1C (NO JUMP) :0049FA12 648F0500000000 POP DWORD PTR FS:[00000000] ---------------------------- coupé -------------------------------- :004A94F2 8B45EC MOV EAX,[EBP-14] :004A94F5 3B45F0 CMP EAX,[EBP-10] :004A94F8 7443 JZ 004A953D <-- on inverse :004A94FA 8A154CEA4A00 MOV DL,[004AEA4C] :004A9500 8B45F8 MOV EAX,[EBP-08] :004A9503 E858EBFFFF CALL 004A8060 :004A9508 8945F4 MOV [EBP-0C],EAX :004A950B 837DF400 CMP DWORD PTR [EBP-0C],00 :004A950F 742C JZ 004A953D (NO JUMP) :004A9511 8D85E4FEFFFF LEA EAX,[EBP-011C] :004A9517 8D95E9FEFFFF LEA EDX,[EBP-0117] :004A951D B9FF000000 MOV ECX,000000FF :004A9522 E8ED11FFFF CALL 0049A714 :004A9527 8B85E4FEFFFF MOV EAX,[EBP-011C] :004A952D E83A14FFFF CALL 0049A96C :004A9532 8B55F4 MOV EDX,[EBP-0C] :004A9535 8B5205 MOV EDX,[EDX+05] :004A9538 E8CBF7FFFF CALL 004A8D08 Donc il y a un saut en 4A94F8 qui ne s'effectue pas. Ensuite il y a le même en 4A950F, et après un fonction affiche le message d'erreur. Mais si on force le saut en 4A94F8 le prog se lance :). Donc voilà où se vérifient l'intégrité du programme. |
Dans l'exemple proposé par TaMaMBoLo, il s'agit de supprimer un Call pour que le Checsum vous soit toujours favorable:
Harmony Assistant by TaMaMBoLo Step 3 :00554120 PUSH ESI :00554121 PUSH EDI :00554122 SUB ESP,18 :00554125 LEA EDI,[ESP+08] :00554129 MOV ESI,006077F8 :0055412E MOVSD :0055412F MOVSD :00554130 MOVSD La routine n'est pas interressante en elle-meme ...Ce qui est interressant,c'est
de savoir d'ou elle vient cette routine...Pour ça,c'est très simple.Quand vous êtes à
l'addresse 554120, Vous tapez A sous softice pour etre dans l'éditeur Asm . Et on entre RET à la
place du push esi . Et on quitte l'éditeur ASm avec escape . Le RET va nous faire sortir de la routine et
on va tomber juste derrière le Call 554120 . :0054BC68 PUSH 00 :0054BC6A CALL 00554120 :0054BC6F POP ECX----- on tombe ici en exécutant le RET :0054BC70 RET On continue la trace avec la touche F10 pour finalement arriver la : :0049CD10 PUSH EBX :0049CD11 PUSH ESI :0049CD12 PUSH EBP :0049CD13 SUB ESP,10 :0049CD16 MOV EBP,[ESP+20] :0049CD1A CALL 004A85F2 :0049CD1F MOV EBX,EAX :0049CD21 MOV EAX,[005E0044]------ On met dans Eax le checksum 1 :0049CD26 CMP EAX,[005E009C]------ On compare le checksum 1 avec le checksum calculé :0049CD2C JNZ 0049CD3B------------ c bon,on saute... :0049CD2E MOV EAX,[005E0130]------ met dans Eax le checksum 2(2ème vérif) :0049CD33 CMP EAX,[005E06C8]------ On compare le checksum 2 avec le checksum calculé :0049CD39 JZ 0049CD4B------------ c bon,on saute... :0049CD3B PUSH 000000D4 :0049CD40 CALL 004A36BD------------ sinon... :0049CD45 POP ECX :0049CD46 CALL 0054BC68------------ le call qui ferme le proggy :0049CD4B PUSH EBX----------------- on est arrivé ici . :0049CD4C CALL 004A5E43 :0049CD51 TEST AL,AL Bon finalement on a attérit en 49CD4B . Juste en remontant légérement
dans le code on voit plein de trucs cools ...En 49CD21 on met le contenu de 5e0044 dans eax . :004D527E 6A04 push 00000004 :004D5280 6A01 push 00000001 :004D5282 689C005E00 push 005E009C---- le premier checksum :004D5287 E894D90600 call 00542C20---- le call qui le calcul :004D528C 83C410 add esp, 00000010 :004D528F 53 push ebx :004D5290 6A04 push 00000004 :004D5292 6A01 push 00000001 :004D5294 68C8065E00 push 005E06C8---- le second checksum :004D5299 E882D90600 call 00542C20---- et le meme call :004D529E 83C410 add esp, 00000010 :004D52A1 6A00 push 00000000 Bon, c'est pas très dur à comprendre : En 4d5280 on sauvegarde le
premier checksum. A cet instant 5e009c=0000000000. Une fois le call 542C20, la case mémoire 5e009c calcul
du deuxième checksum , c'est le meme call 542C20 ... Et si on vire ces deux calls,les valeurs dans 5e009c
et 5e06c8 seront toujours égales à 0, non ? Il ne nous reste plus qu'a trouver l'autre endroit où
sont recalculés les checksums ... |
WinDelete et Splash (VBOX protected) by Christal Le checksum :070066EA 8BC3 mov eax, ebx :070066EC 33FB xor edi, ebx :070066EE F7D0 not eax :070066F0 3145B0 xor dword ptr [ebp-50], eax :070066F3 8D85F0FDFFFF lea eax, dword ptr [ebp-210] :070066F9 50 push eax :070066FA 8D8520FFFFFF lea eax, dword ptr [ebp-E0] :07006700 81F7494C0000 xor edi, 00004C49 :07006706 50 push eax :07006707 57 push edi <- longueur du code :07006708 33F3 xor esi, ebx :0700670A FF75B0 push [ebp-50] :0700670D 81F64A570000 xor esi, 0000574A :07006713 8975C4 mov dword ptr [ebp-3C], esi :07006716 89BD0CFFFFFF mov dword ptr [ebp+FFFFFF0C], edi :0700671C 56 push esi <- Code RVA :0700671D FF7584 push [ebp-7C] :07006720 E843120000 call 07007968 et ici. Les paramètres sont les mêmes: :070071B2 8D8514FEFFFF lea eax, dword ptr [ebp+FFFFFE14] :070071B8 C645FC23 mov [ebp-04], 23 :070071BC 50 push eax :070071BD 8D8520FFFFFF lea eax, dword ptr [ebp+FFFFFF20] :070071C3 50 push eax :070071C4 FFB50CFFFFFF push dword ptr [ebp+FFFFFF0C] :070071CA FF75B0 push [ebp-50] :070071CD FF75C4 push [ebp-3C] :070071D0 FF7584 push [ebp-7C] :070071D3 E890070000 call 07007968 Rappelez vous que les BPX actifs changent les paramètres, aussi, effacez
tous les breakpoints avant ces calls :07006F62 8D458C lea eax, dword ptr [ebp-74] :07006F65 50 push eax :07006F66 8D8504FFFFFF lea eax, dword ptr [ebp+FFFFFF04] :07006F6C 50 push eax :07006F6D A138FE0407 mov eax, dword ptr [0704FE38] :07006F72 FF7028 push [eax+28] :07006F75 E836DF0000 call 07014EB0 Un autre contrôle est réalisé à l'intérieur de Vboxb410.dll, et envoi le résultat qu'il à trouvé à PreviewParadise sous la formes d'une combinaison à 2 paramètres: :070072D8 8B450C mov eax, dword ptr [ebp+0C] :070072DB 8B4D2C mov ecx, dword ptr [ebp+2C] :070072DE F7D0 not eax :070072E0 33C8 xor ecx, eax <- 1=OK :070072E2 7510 jne 070072F4 Quand vous aurez réussi ces modifications en mémoires, il ne vous restera plus qu'à utiliser votre éditeur hexadécimal. |