Ultima modifica da un moderatore:
Ciao a tutti, vi propongo questo semplicissimo crackme scritto ad un amico (tameo). Ho pensato di risolverlo ed usarlo come tutorial.
Linguaggio C
Regole: trovare la password giusta. Patching non consentito
DOWNLOAD
provate da soli se non riuscite leggete il tutorial:
TUTORIAL:
spero di aver spiegato il codice asm in modo sufficentemente comprensibile, se avete dubbi o domande non esitate a chiedere.
Predator
Linguaggio C
Regole: trovare la password giusta. Patching non consentito
DOWNLOAD
provate da soli se non riuscite leggete il tutorial:
TUTORIAL:
Se non avete OllyDgb scaricatelo dal sito ufficilale, ricordo che per ora la versione 1.10 è migliore della 2.0
www.ollydbg.de
Buttatelo in pasto ad Olly. Se ricerchiamo le stringhe
tasto destro Search for-> All referenced text strings
sta volta non troveremo una beata fava pertanto le stringhe devono per forza essere generate in qualche altro modo, vediamo di andare oltre con l'analisi del codice.
La prima domanda che ci poniamo è: come facciamo a sapere dove andar guardare? NO!
la prima domanda è: con che linguaggio è scritto? per conoscere la risposta ci sono essenzialmente due modi
1) riconoscere al volo il codice debuggato
2) avvalersi di un analizzatore. A fronte di questo vi rimando a RDG Packer Detector
RDGMax - RDGSoFT
se non è presente il link di download intanto vi propongo la versione 6.6 2k8 RDG DOWNLOAD
proseguiamo
giusto per curiosità analizziamolo e vediamo cosa ci dice RDG: compilatore Dev-C++
proseguiamo:
La logica suggerisce di vedere come la domanda e la risposta vengono mostrate e da li proseguire:
in C++ che cosa mostra nella finestra dos un stringa? la funzione printf pertanto se noi mettessimo un breakpoint su tutti i printf arriveremo vicino a cioò che ci interessa.
Ci sono 3 modi per trovare una CALL (una funzione):
-cercarle a mano sfogliando il codice
-mettere un breakpoint su tutte le CALL tramite commandline
-mettere uno o piu' breakpoint scegliendo le CALL da un elenco... in questo caso opto per questa
***
apro una parentesi: notate in basso a sinistra nel dump cosa vediamo? tho c'è scritto "abcdefghijklmnopqrstuvwxyz :", chissà a che serve?
chiusa parentesi, la riprendiamo dopo
***
dunque siamo nella finestra del codice premete tasto destro e scegliete: Scearch for-> All intermodulars call
cioè tutte le chiamate intermodulari, ovvero CALL personali e chiamate alle API di sistema operativo,
questa è la lista di questo crackme:
le mie non sono ordinate per offset perchè prima di incollare ho semplicemente premuto sulla colonna Destination, in questo modo le call dello stesso tipo sono tutte vicine.
vedete queste?:
premete F2 su ognuna di esse in modo da settare un breakpoint, ora runniamo con F9
Olly breka subito sull'offset 0040139F
0040139F CALL <jmp.&msvcrt.printf> ; printf
salite qualche riga piu' su, vedete che il comando è come "racchiuso" in un ciclo, mi riferisco a questa porzione di codice:
ovviamente questo codice fa qualcos che permette alla printf di mostrare a video la prima frase, cioè "dammi la password:"
Per seguire al meglio tutta l'operazione dall'inizio mettete un bp (breakpoint) sulla prima istruzione: 00401379 CMP DWORD PTR SS:[EBP-20C], 11
Premiamo CTRL+F2 per ricaricare il progetto e runniamo ancora con F9
questa volta siamo fermi prima... Dato che siete all'inizio vi spiegherò bene cosa fa il codice C++ disassemblato leggendovi l'asm ritornato per bene. Perchè un reverser è proporzionalmente bravo al suo grado di capire il codice.
ora proseguite premendo F8, cosi procediamo per step
00401379 CMP DWORD PTR SS:[EBP-20C], 11 <--- (CMP significa confrontare è come un IF) esegue un confronto con cio' che trovera' nello stack all'indirizzo EBP - 20C (ricordate che tutto cio' che vedete è esadecimale e non decimale percio' 20C = 524 ma non ve ne importa di questo, mentre EBP è il valore di uno dei registri)
riprendo, esegue un contro tra l'indirzzo e il valore 11 (esadecimale cioè 18 in decimale), per farla semplce praticamente siamo all'interno di un ciclo for che va da 0 a 18
proseguo
00401380 JG SHORT 004013AE <--- Salto condizionato: "Salta se è maggiore di" cioè esegui il salto se EAX è maggiore di 11 (18 in decimale)
00401382 MOV EAX, DWORD PTR SS:[EBP-20C] <---(MOV mette dei valori dal secondo operando nel primo) Mette in EAX il valore dello stack presente all'offset EBP-20C, in questo caso è 0
pratiamente inizializza a zero EAX
00401388 MOV EAX, DWORD PTR SS:[EBP+EAX*4-58] <--- come sopra ma questa volta in EBP+EAX*4-58 c'è un valore che cosa?
semplice lo vediamo nel riquadro subito sotto il codide:
Stack SS:[0022FF20]=00000003
EAX=00000000
significa che ora in EAX c'è 00000000 e andra' a metterci 3
0040138C ADD EAX, 00402000 <--- (ADD esegue una somma) aggiunge al valore contenuto in EAX, il valore esadecimale 402000
attenzione cosa ci sarà mai la? non dobbiamo nemmeno fare la fatica di cercare nel dump, basta abbassare gli occhi che è ancora li
402000+3= 402003 che corrisponde alla posizione della lettera "d". I piu' svegli avranno già capito che il ciclo passa un array di valori che puntano alle lettere che compongono le frasi
00401391 MOVSX EAX, BYTE PTR DS:[EAX] <--- (MOVSX mette un dato a 8 o 16 bit in una destinazione a 16 o 32 bit) prende il valore AL QUALE PUNTA EAX e lo mette in EAX stesso cioè mette in eax 64h che in decimale è 100 che corrisponde alla lettera "d" in ascii, poi lo vediamo subito
ora attenzione ci sono 3 righe da analizzare assieme perchè compongono la funzione printf che funziona per esempio cosi:
printf("%c",carattere);
percio' dobbiamo passare alla funzione 2 valori e poi richiamarla, ecco cosa succede
00401394 MOV DWORD PTR SS:[ESP+4], EAX <---mette nello sposta avanti lo stack di 4 (cioè una DWORD) e ci mette il valore di EAX (cioè 64h). prima di premere F8 guardate lo stack (finestra in basso a destra), guardate la seconda riga. ora premete F8. come vedete è apparso 64
perchè come vi ho detto ha spostato lo stack di 4 e ha messo il valore in esso.
00401398 MOV DWORD PTR SS:[ESP], 00403000 <--- come prima, ma senza spostarsi nello stack, mette il valore che trova a 403000h, cioè "%c"
0040139F CALL <jmp.&msvcrt.printf> <--- esegue la printf
per venire al lato pratico la printf sta stampando a video il carattere 'd'
004013A4 LEA EAX, DWORD PTR SS:[EBP-20C] <---muove in eax il valore dello stack al momento è 1
004013AA INC DWORD PTR DS:[EAX] <--- incrementa eax di 1
004013AC JMP SHORT 00401379 <--- salta in su all'offset 401379h dove c'è la riga con il CMP
il ciclo si ripete!!!
ora potete scendere con F8 da soli
noterete che:
il salto JG non verra' effettuato fino a quando il contatore sarà 11
il ciclo prelevera' dall'array tutti i valori che poi printf manderà a video
poi quando il contatore arrivera' a 12 allora sara' maggiore di 11 (ma va?) e il JG eseguira' il salto uscendo dal ciclo
tutto questo comporra' la frase "dammi la password :"
poco piu' giu' la funzione scanf ci mettera' in attesa della password
mettete un bp su 004013D0 subito dopo la scanf, scrivete "pippo" come password e premete invio
ora scendete con F8 e vediamo l'inizio di un altro ciclo piu' grande... anzi a guardare bene sono due cicli for uno dentro l'altro.
simile a prima vediamo cosa fa:
004013DA CMP DWORD PTR SS:[EBP-20C], 6 <--- va da 0 a 6, cioè controlla 7 caratteri
004013E1 JG 00401470 <--- se è il 7 salta altrimenti prosegue
004013E7 LEA EAX, DWORD PTR SS:[EBP-8] <--- (LEA da lo stesso risultato di MOV ma si usa un po diversamente, lo vedremo)
004013EA ADD EAX, DWORD PTR SS:[EBP-20C]
004013F0 LEA ECX, DWORD PTR DS:[EAX-200] <--- mette in ECX l'indirizzo nel quale risiede la pass inserita "pippo"
004013F6 MOV EAX, DWORD PTR SS:[EBP-20C]
004013FC MOV EDX, DWORD PTR SS:[EBP+EAX*4-D8]
00401403 ADD EDX, 00402000
in pratica fino a qui fa la stessa cosa di prima, sposta mette valori nei registri EAX, ECX e EDX prendendoli dallo stack
00401409 MOVZX EAX, BYTE PTR DS:[ECX] <--- prepara l'analisi con la prima lettera
0040140C CMP AL, BYTE PTR DS:[EDX] <--- confronta i valori, nel nostro caso sono questi:
DS:[00402006]=67 ('g')
AL=70 ('p')
0040140E JE SHORT 00401463 <--- se i valori sono uguali non esegue il salto, altrimenti si ed uscira' dal ciclo. Ovviamente avendo messo "pippo" uscirà entrando nel ciclo che scrive "password errata" (sempre attraverso un ciclo).
per non uscire dal ciclo possiamo forzarlo modificando il salto condizionale JE con un salto forzato JMP, percio andiamo su
0040140E JE SHORT 00401463
premiamo la barra spaziatrice e modifichiamo JE in JMP
0040140E JMP SHORT 00401463
in questo modo il ciclo continuera' fino la sua fine e all'ffset 0040140C
0040140C CMP AL, BYTE PTR DS:[EDX]
possiamo leggere tutte le lettere che vengono confrontate, una ad una, cioè goodjob.
ovviamente avendo messo JMP al posto di JE il programma continuera' la sua esecuzione credendo di aver ricevuto la password giusta. Ma ora la conosciamo
I ragionamenti potrebbero sembrare difficili, ma in realtà un reverser alle prime armi, già dopo un po di tempo arriva a questa soluzione quasi subito, l'importante è non voler mai fare il passo piu' lungo della gamba e procedere per livelli.
ah io ho capito subito che la pass era qui
è solo questione di apprendimento e confidenza
www.ollydbg.de
Buttatelo in pasto ad Olly. Se ricerchiamo le stringhe
tasto destro Search for-> All referenced text strings
sta volta non troveremo una beata fava pertanto le stringhe devono per forza essere generate in qualche altro modo, vediamo di andare oltre con l'analisi del codice.
La prima domanda che ci poniamo è: come facciamo a sapere dove andar guardare? NO!
la prima domanda è: con che linguaggio è scritto? per conoscere la risposta ci sono essenzialmente due modi
1) riconoscere al volo il codice debuggato
2) avvalersi di un analizzatore. A fronte di questo vi rimando a RDG Packer Detector
RDGMax - RDGSoFT
se non è presente il link di download intanto vi propongo la versione 6.6 2k8 RDG DOWNLOAD
proseguiamo
giusto per curiosità analizziamolo e vediamo cosa ci dice RDG: compilatore Dev-C++
proseguiamo:
La logica suggerisce di vedere come la domanda e la risposta vengono mostrate e da li proseguire:
in C++ che cosa mostra nella finestra dos un stringa? la funzione printf pertanto se noi mettessimo un breakpoint su tutti i printf arriveremo vicino a cioò che ci interessa.
Ci sono 3 modi per trovare una CALL (una funzione):
-cercarle a mano sfogliando il codice
-mettere un breakpoint su tutte le CALL tramite commandline
-mettere uno o piu' breakpoint scegliendo le CALL da un elenco... in questo caso opto per questa
***
apro una parentesi: notate in basso a sinistra nel dump cosa vediamo? tho c'è scritto "abcdefghijklmnopqrstuvwxyz :", chissà a che serve?
chiusa parentesi, la riprendiamo dopo
***
dunque siamo nella finestra del codice premete tasto destro e scegliete: Scearch for-> All intermodulars call
cioè tutte le chiamate intermodulari, ovvero CALL personali e chiamate alle API di sistema operativo,
questa è la lista di questo crackme:
Codice:
Found intermodular calls
Address Disassembly Destination
00401220 crackme.<ModuleEn PUSH EBP (Initial CPU selection)
00401900 CALL <JMP.&msvcrt.abort> msvcrt.abort
00401982 CALL <JMP.&msvcrt.abort> msvcrt.abort
0040189F CALL NEAR DWORD PTR DS:[<&KERNEL32.AddAtomA>] kernel32.AddAtomA
004011E9 CALL <JMP.&msvcrt._cexit> msvcrt._cexit
004011F1 CALL <JMP.&KERNEL32.ExitProcess> kernel32.ExitProcess
0040197D CALL <JMP.&msvcrt.fflush> msvcrt.fflush
00401777 CALL NEAR DWORD PTR DS:[<&KERNEL32.FindAtomA>] kernel32.FindAtomA
004018C0 CALL NEAR DWORD PTR DS:[<&KERNEL32.FindAtomA>] kernel32.FindAtomA
0040196D CALL <JMP.&msvcrt.fprintf> msvcrt.fprintf
004018B8 CALL <JMP.&msvcrt.free> msvcrt.free
0040164F CALL NEAR DWORD PTR DS:[<&KERNEL32.GetAtomNameA>] kernel32.GetAtomNameA
00401452 CALL <JMP.&msvcrt._getch> msvcrt._getch
004014B2 CALL <JMP.&msvcrt._getch> msvcrt._getch
0040114A CALL <JMP.&msvcrt.__getmainargs> msvcrt.__getmainargs
00401798 CALL <JMP.&msvcrt.malloc> msvcrt.malloc
004012DD CALL <JMP.&msvcrt.memcpy> msvcrt.memcpy
0040139F CALL <JMP.&msvcrt.printf> msvcrt.printf
004013B5 CALL <JMP.&msvcrt.printf> msvcrt.printf
00401443 CALL <JMP.&msvcrt.printf> msvcrt.printf
004014A3 CALL <JMP.&msvcrt.printf> msvcrt.printf
004011C5 CALL <JMP.&msvcrt.__p__environ> msvcrt.__p__environ
004011B0 CALL <JMP.&msvcrt.__p__fmode> msvcrt.__p__fmode
004013CB CALL <JMP.&msvcrt.scanf> msvcrt.scanf
00401185 CALL <JMP.&msvcrt._setmode> msvcrt._setmode
004011AB CALL <JMP.&msvcrt._setmode> msvcrt._setmode
00401206 CALL <JMP.&msvcrt._setmode> msvcrt._setmode
00401111 CALL <JMP.&KERNEL32.SetUnhandledExceptionFilter> kernel32.SetUnhandledExceptionFilter
0040122D CALL NEAR DWORD PTR DS:[<&msvcrt.__set_app_type>] msvcrt.__set_app_type
0040124D CALL NEAR DWORD PTR DS:[<&msvcrt.__set_app_type>] msvcrt.__set_app_type
00401037 CALL <JMP.&msvcrt.signal> msvcrt.signal
00401094 CALL <JMP.&msvcrt.signal> msvcrt.signal
004010BD CALL <JMP.&msvcrt.signal> msvcrt.signal
004010E7 CALL <JMP.&msvcrt.signal> msvcrt.signal
vedete queste?:
Codice:
0040139F CALL <JMP.&msvcrt.printf> msvcrt.printf
004013B5 CALL <JMP.&msvcrt.printf> msvcrt.printf
00401443 CALL <JMP.&msvcrt.printf> msvcrt.printf
004014A3 CALL <JMP.&msvcrt.printf> msvcrt.printf
Olly breka subito sull'offset 0040139F
0040139F CALL <jmp.&msvcrt.printf> ; printf
salite qualche riga piu' su, vedete che il comando è come "racchiuso" in un ciclo, mi riferisco a questa porzione di codice:
Codice:
00401379 CMP DWORD PTR SS:[EBP-20C], 11 ; |
00401380 JG SHORT 004013AE ; |
00401382 MOV EAX, DWORD PTR SS:[EBP-20C] ; |
00401388 MOV EAX, DWORD PTR SS:[EBP+EAX*4-58] ; |
0040138C ADD EAX, 00402000 ; |
00401391 MOVSX EAX, BYTE PTR DS:[EAX] ; |
00401394 MOV DWORD PTR SS:[ESP+4], EAX ; |
00401398 MOV DWORD PTR SS:[ESP], 00403000 ; |%c\n%*s
0040139F CALL <JMP.&msvcrt.printf> ; \printf
004013A4 LEA EAX, DWORD PTR SS:[EBP-20C]
004013AA INC DWORD PTR DS:[EAX]
004013AC JMP SHORT 00401379
Per seguire al meglio tutta l'operazione dall'inizio mettete un bp (breakpoint) sulla prima istruzione: 00401379 CMP DWORD PTR SS:[EBP-20C], 11
Premiamo CTRL+F2 per ricaricare il progetto e runniamo ancora con F9
questa volta siamo fermi prima... Dato che siete all'inizio vi spiegherò bene cosa fa il codice C++ disassemblato leggendovi l'asm ritornato per bene. Perchè un reverser è proporzionalmente bravo al suo grado di capire il codice.
ora proseguite premendo F8, cosi procediamo per step
00401379 CMP DWORD PTR SS:[EBP-20C], 11 <--- (CMP significa confrontare è come un IF) esegue un confronto con cio' che trovera' nello stack all'indirizzo EBP - 20C (ricordate che tutto cio' che vedete è esadecimale e non decimale percio' 20C = 524 ma non ve ne importa di questo, mentre EBP è il valore di uno dei registri)
riprendo, esegue un contro tra l'indirzzo e il valore 11 (esadecimale cioè 18 in decimale), per farla semplce praticamente siamo all'interno di un ciclo for che va da 0 a 18
proseguo
00401380 JG SHORT 004013AE <--- Salto condizionato: "Salta se è maggiore di" cioè esegui il salto se EAX è maggiore di 11 (18 in decimale)
00401382 MOV EAX, DWORD PTR SS:[EBP-20C] <---(MOV mette dei valori dal secondo operando nel primo) Mette in EAX il valore dello stack presente all'offset EBP-20C, in questo caso è 0
pratiamente inizializza a zero EAX
00401388 MOV EAX, DWORD PTR SS:[EBP+EAX*4-58] <--- come sopra ma questa volta in EBP+EAX*4-58 c'è un valore che cosa?
semplice lo vediamo nel riquadro subito sotto il codide:
Stack SS:[0022FF20]=00000003
EAX=00000000
significa che ora in EAX c'è 00000000 e andra' a metterci 3
0040138C ADD EAX, 00402000 <--- (ADD esegue una somma) aggiunge al valore contenuto in EAX, il valore esadecimale 402000
attenzione cosa ci sarà mai la? non dobbiamo nemmeno fare la fatica di cercare nel dump, basta abbassare gli occhi che è ancora li
Codice:
00402000 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 abcdefghijklmnop
00402010 71 72 73 74 75 76 77 78 79 7A 20 3A 03 00 00 00 qrstuvwxyz :....
00401391 MOVSX EAX, BYTE PTR DS:[EAX] <--- (MOVSX mette un dato a 8 o 16 bit in una destinazione a 16 o 32 bit) prende il valore AL QUALE PUNTA EAX e lo mette in EAX stesso cioè mette in eax 64h che in decimale è 100 che corrisponde alla lettera "d" in ascii, poi lo vediamo subito
Codice:
DS:[00402003]=64 ('d')
EAX=00402003 (crackme.00402003)
ora attenzione ci sono 3 righe da analizzare assieme perchè compongono la funzione printf che funziona per esempio cosi:
printf("%c",carattere);
percio' dobbiamo passare alla funzione 2 valori e poi richiamarla, ecco cosa succede
00401394 MOV DWORD PTR SS:[ESP+4], EAX <---mette nello sposta avanti lo stack di 4 (cioè una DWORD) e ci mette il valore di EAX (cioè 64h). prima di premere F8 guardate lo stack (finestra in basso a destra), guardate la seconda riga. ora premete F8. come vedete è apparso 64
perchè come vi ho detto ha spostato lo stack di 4 e ha messo il valore in esso.
00401398 MOV DWORD PTR SS:[ESP], 00403000 <--- come prima, ma senza spostarsi nello stack, mette il valore che trova a 403000h, cioè "%c"
0040139F CALL <jmp.&msvcrt.printf> <--- esegue la printf
per venire al lato pratico la printf sta stampando a video il carattere 'd'
004013A4 LEA EAX, DWORD PTR SS:[EBP-20C] <---muove in eax il valore dello stack al momento è 1
004013AA INC DWORD PTR DS:[EAX] <--- incrementa eax di 1
004013AC JMP SHORT 00401379 <--- salta in su all'offset 401379h dove c'è la riga con il CMP
il ciclo si ripete!!!
ora potete scendere con F8 da soli
noterete che:
il salto JG non verra' effettuato fino a quando il contatore sarà 11
il ciclo prelevera' dall'array tutti i valori che poi printf manderà a video
poi quando il contatore arrivera' a 12 allora sara' maggiore di 11 (ma va?) e il JG eseguira' il salto uscendo dal ciclo
tutto questo comporra' la frase "dammi la password :"
poco piu' giu' la funzione scanf ci mettera' in attesa della password
mettete un bp su 004013D0 subito dopo la scanf, scrivete "pippo" come password e premete invio
ora scendete con F8 e vediamo l'inizio di un altro ciclo piu' grande... anzi a guardare bene sono due cicli for uno dentro l'altro.
simile a prima vediamo cosa fa:
004013DA CMP DWORD PTR SS:[EBP-20C], 6 <--- va da 0 a 6, cioè controlla 7 caratteri
004013E1 JG 00401470 <--- se è il 7 salta altrimenti prosegue
004013E7 LEA EAX, DWORD PTR SS:[EBP-8] <--- (LEA da lo stesso risultato di MOV ma si usa un po diversamente, lo vedremo)
004013EA ADD EAX, DWORD PTR SS:[EBP-20C]
004013F0 LEA ECX, DWORD PTR DS:[EAX-200] <--- mette in ECX l'indirizzo nel quale risiede la pass inserita "pippo"
004013F6 MOV EAX, DWORD PTR SS:[EBP-20C]
004013FC MOV EDX, DWORD PTR SS:[EBP+EAX*4-D8]
00401403 ADD EDX, 00402000
in pratica fino a qui fa la stessa cosa di prima, sposta mette valori nei registri EAX, ECX e EDX prendendoli dallo stack
00401409 MOVZX EAX, BYTE PTR DS:[ECX] <--- prepara l'analisi con la prima lettera
0040140C CMP AL, BYTE PTR DS:[EDX] <--- confronta i valori, nel nostro caso sono questi:
DS:[00402006]=67 ('g')
AL=70 ('p')
0040140E JE SHORT 00401463 <--- se i valori sono uguali non esegue il salto, altrimenti si ed uscira' dal ciclo. Ovviamente avendo messo "pippo" uscirà entrando nel ciclo che scrive "password errata" (sempre attraverso un ciclo).
per non uscire dal ciclo possiamo forzarlo modificando il salto condizionale JE con un salto forzato JMP, percio andiamo su
0040140E JE SHORT 00401463
premiamo la barra spaziatrice e modifichiamo JE in JMP
0040140E JMP SHORT 00401463
in questo modo il ciclo continuera' fino la sua fine e all'ffset 0040140C
0040140C CMP AL, BYTE PTR DS:[EDX]
possiamo leggere tutte le lettere che vengono confrontate, una ad una, cioè goodjob.
ovviamente avendo messo JMP al posto di JE il programma continuera' la sua esecuzione credendo di aver ricevuto la password giusta. Ma ora la conosciamo
I ragionamenti potrebbero sembrare difficili, ma in realtà un reverser alle prime armi, già dopo un po di tempo arriva a questa soluzione quasi subito, l'importante è non voler mai fare il passo piu' lungo della gamba e procedere per livelli.
ah io ho capito subito che la pass era qui
Codice:
00401329 MOV DWORD PTR SS:[EBP-D8], 6
00401333 MOV DWORD PTR SS:[EBP-D4], 0E
0040133D MOV DWORD PTR SS:[EBP-D0], 0E
00401347 MOV DWORD PTR SS:[EBP-CC], 3
00401351 MOV DWORD PTR SS:[EBP-C8], 9
0040135B MOV DWORD PTR SS:[EBP-C4], 0E
00401365 MOV DWORD PTR SS:[EBP-C0], 1
0040136F MOV DWORD PTR SS:[EBP-20C], 0
Predator