This crackme starts by XOR'ing 1200h bytes starting at 402000:
CODE:00401000 mov ecx, 1200h CODE:00401005 mov edi, offset unk_402000 CODE:0040100A mov esi, edi CODE:0040100C CODE:0040100C loc_40100C: CODE:0040100C lodsb CODE:0040100D xor al, 21h CODE:0040100F stosb CODE:00401010 loop loc_40100C
and then it installs the exception handler:
CODE:00401012 call sub_40107C CODE:00401017 CODE:00401017 exception_handler: ....
disassembly with opcodes:
CODE:0040107C 64 67 FF 36 00 00 push dword ptr fs:0 CODE:00401082 64 67 89 26 00 00 mov fs:0, esp CODE:00401088 60 pusha CODE:00401089 9C pushf CODE:0040108A 33 C0 xor eax, eax CODE:0040108C E8 09 00 00 00 call near ptr loc_401099+1 CODE:00401091 E8 E8 23 00 00 call near ptr unk_40347E CODE:00401096 00 7A 23 add [edx+23h], bh CODE:00401096 sub_40107C endp CODE:00401096 CODE:00401099 CODE:00401099 loc_401099: CODE:00401099 A0 8B 04 24 EB mov al, ds:0EB24048Bh CODE:0040109E 03 7A 29 add edi, [edx+29h] CODE:004010A1 E9 C6 00 90 C3 jmp near ptr 0C3D0116Ch
so, what we have here is an unaligned disassembly. Since this will be a
recurring problem throughout this crackme, we can run a script
correct_calls1.idc:
auto a;
auto i;
auto b;
i = 0x401044;
a = 0x00;
b = 0x00;
while(a != 0xffffffff){
a = FindBinary(i, 0x01, "A0 8B 04 24");
if(a != b){
MakeUnkn(a, 0);
PatchByte(a, 0x90);
MakeCode(a+1);
Message("Byte Patched at:%x\n",a);
b = a;
}
i = i+1;
}
We look for the bytes A0 8B 04 24. Why is this? At CODE:0040108C call near ptr loc_401099+1
we're calling a procedure at 401099+1, and at 401099 we have the following bytes:
CODE:00401099 A0 8B 04 24 EB, since 8B is the opcode for call, and A0 is going to be ignored, and since A0 is the opcode for mov, which takes arguments, if we can NOP A0 and tell IDA to "define as code" at 8B, then the disassembly must resemble more closely our program, let's try it by hand:
If we undefine the code at 401099, and then define it at 401099+1 we go from this:
CODE:00401099 A0 8B 04 24 EB mov al, ds:0EB24048Bh
to:
CODE:0040109A loc_40109A: CODE:0040109A 8B 04 24 mov eax, [esp] CODE:0040109D EB 03 jmp short loc_4010A2
and at loc_4010A2 we can see that the code has become:
CODE:004010A2 loc_4010A2: CODE:004010A2 C6 00 90 mov byte ptr [eax], 90h CODE:004010A5 C3 retn
so, in eax we have the return address (which is 00401091 which is the address right
after our call to 401099+1), and we are NOP'ing the instruction (mov byte ptr [eax], 90h),
so instead of having
CODE:00401091 E8 E8 23 00 00 call near ptr unk_40347Eas the instruction to which we will return, we will actually have:
CODE:00401092 E8 23 00 00 00 call near ptr dword_4010AC+0Eh CODE:00401097 7A 23 jp short near ptr dword_4010AC+10h
since at 401091 we will have a NOP which is a 0 argument instruction and this is why we want to run our second script:
We can run the nop_ret.idc script, so that all the return
addresses from dummy calls appear as NOP'ed
nop_ret.idc:
auto a;
auto i;
auto b;
auto c;
auto failed;
i = 0x401044;
a = 0x00;
b = 0x00;
failed = 0;
while(a != 0xffffffff){
a = FindBinary(i, 0x01, "E8 E8 23");
if(a != b){
MakeUnkn(a, 0);
PatchByte(a, 0x90);
c = MakeCode(a+1);
if(c == 0)
failed = failed + 1;
Message("Byte Patched at:%x with ret = %d\n",a, c);
b = a;
}
i = i+1;
}
Message("%d conversions Failed\n", failed);
this script however, fails in the following addresses,
where I corrected by hand:
addr addr+1 instruction @ addr+1 | word @ call_arg
401091 | 401092 | call near ptr dword_4010AC+0Eh | EBE908EBh
40134f | 401350 | call near ptr dword_401364+14h | DB8B4000h
4017b0 | 4017b1 | call near ptr dword_4017CC+0Dh | F7EBE908h
4018d8 | 4018d9 | call near ptr dword_4018F4+0Dh | F7EBE908h
Ok let's take a look at what happens in 401091, for instance:
After running the script, we have this:
call near ptr dword_4010AC+0Eh
If we go to 4010AC and undefine the code and define the code at
4010AC+E this is what we see:
CODE:004010BA locret_4010BA: CODE:004010BA C3 retn
so ... we go back to the return address:
CODE:00401097 7A 23 jp short near ptr unk_4010BCwe take the jump, and define as code:
CODE:004010BC loc_4010BC: CODE:004010BC 7A E9 jp short near ptr word_4010A6+1 CODE:004010BE loc_4010BE: CODE:004010BE 70 DA jo short sub_40109A CODE:004010C0 7B D1 jnp short near ptr loc_401092+1 CODE:004010C2 71 F3 jno short loc_4010B7
so once again, let's look at 4010A6+1:
(undefine code @ 4010A6, define code at 4010A7)
CODE:004010A7 70 F0 jo short near ptr unk_401099 CODE:004010A9 87 D2 xchg edx, edx CODE:004010AB 71 07 jno short loc_4010B4
We can automate this process through the following script:
correct_calls2.idc
auto a;
auto i;
auto b;
i = 0x401044;
a = 0x00;
b = 0x00;
while(a != 0xffffffff){
a = FindBinary(i, 0x01, "70 F0 87 D2");
if(a != b){
MakeUnkn(a, 0);
MakeCode(a);
Message("Byte Patched at:%x\n",a);
b = a;
}
i = i+1;
}
So, thus far we have XOR'ed 1200h bytes of data, and set an exception
handler. After stepping through a couple of instructions, we arrive at
CODE:004010CC mov esi, offset unk_402000 .... CODE:00401114 popa CODE:00401115 push 4 CODE:00401117 push 1000h CODE:0040111C push 6000h CODE:00401121 push 0 CODE:00401123 call VirtualAlloc
LPVOID WINAPI VirtualAlloc( __in_opt LPVOID lpAddress, __in SIZE_T dwSize, __in DWORD flAllocationType, __in DWORD flProtect );
Reserves or commits a region of pages in the virtual address space of
the calling process. Memory allocated by this function is automatically
initialized to zero, unless MEM_RESET is specified.
6000h bytes of memory are being allocated with AllocationType set to 1000h and flProtect set to 4. From msdn:
flAllocationType = 1000h - Allocates physical storage in memory or in the paging file on disk for the specified reserved memory pages. The function initializes the memory to zero.
flpProtect = 4 - Enables execute, read-only, or read/write access to the committed region of pages
afterwards there is a call to mojo1 CODE:00401133 call mojo1 mojo1 is
responsible to read the previously XOR'ed data, make changes to it, and
write it in the virtualalloc allocated chunck of memory. When mojo1
ends, we have what seems like a PE in the allocated chunck of memory.
and then the memory chunck's contents are written to a file named
DBG.VXD (004011FF)
At
ODE:004012AA popf CODE:004012AB popa CODE:004012AC push 0 CODE:004012AE push 4000000h CODE:004012B3 push 0 CODE:004012B5 push 0 CODE:004012B7 push 0 CODE:004012B9 push 0 CODE:004012BB push esi CODE:004012BC call CreateFileA CODE:004012C1 or eax, eax
We check if we can get an handle for the file. If we can't get it, we
can create our window with 004012F7 as our call back function for event
handling.
In our call back function, we're interested in wm_command
CODE:00401318 case_wm_command: CODE:00401318 cmp ax, 111h CODE:0040131C jnz short case_WM_INITDIALOG CODE:0040131E jmp loc_40143C CODE:0040143C loc_40143C: CODE:0040143C cmp word ptr [ebp+arg_8], 9 CODE:00401441 jz loc_4014E2 CODE:00401447 cmp word ptr [ebp+arg_8], 3E8h CODE:0040144D jnz short loc_401457 CODE:0040144F push [ebp+hDlg] CODE:00401452 call call_getDlgItem CODE:00401457 CODE:00401457 loc_401457: CODE:00401457 cmp word ptr [ebp+arg_8], 3E9h CODE:0040145D jnz short loc_401467 CODE:0040145F push [ebp+hDlg] CODE:00401462 call call_getDlgItem CODE:00401467 CODE:00401467 loc_401467: CODE:00401467 cmp [ebp+arg_8], 1 CODE:0040146B jz short near ptr CHECK_PRESSED CODE:0040146D
We can also see that call_getDlgItem is coded as
CODE:00401474 call_getDlgItem proc near CODE:00401474 CODE:00401474 CODE:00401474 hDlg = dword ptr 8 CODE:00401474 CODE:00401474 enter 0, 0 CODE:00401478 push ebx CODE:00401479 push ecx CODE:0040147A push edx CODE:0040147B push 28h CODE:0040147D push offset String CODE:00401482 push 3E8h CODE:00401487 push [ebp+hDlg] CODE:0040148A call GetDlgItemTextA CODE:0040148F mov edi, offset String CODE:00401494 push 28h CODE:00401496 push (offset String+28h) CODE:0040149B push 3E9h CODE:004014A0 push [ebp+hDlg] CODE:004014A3 call GetDlgItemTextA CODE:004014A8 mov edi, offset String CODE:004014AD pop edx CODE:004014AE pop ecx CODE:004014AF pop ebx CODE:004014B0 leave CODE:004014B1 retn 4 CODE:004014B1 call_getDlgItem endp
which means that basically everytime we type something, it is copied to
String and String+28h, so the first 0x28 bytes of String hold the
username, from String+0x28 until String+0x50 is where the entered serial
resides.
After we've typed username and serial, we will press the Check button,
and we will jump to "CHECK_PRESSED"
CODE:00401467 cmp [ebp+arg_8], 1 CODE:0040146B jz short near ptr CHECK_PRESSED CODE:004014DB CHECK_PRESSED db 8Dh CODE:004014DC dd 0CBE9C0h CODE:004014E0 db 2 dup(0)
at CHECK_PRESSED an illegal instruction is going to take place, so we
should set a breakpoint at our exception handler, and analyze what is
going on in there.
The Exception Handler:
CODE:00401017 except_handler: CODE:00401017 pusha CODE:00401018 mov eax, [esp+20h+arg_0] ; struct _EXCEPTION_RECORD CODE:0040101C mov ebx, [esp+20h+arg_8] ; struct _CONTEXT CODE:00401020 cmp dword ptr [eax], 0C000001Dh CODE:00401026 jz short illegal_inst_excp CODE:00401028 cmp dword ptr [eax], 0C0000005h CODE:0040102E jz short access_viol_excp CODE:00401030 CODE:00401030 loc_401030: CODE:00401030 CODE:00401030 popa CODE:00401031 xor eax, eax CODE:00401033 retn CODE:00401034 ; --------------------------------------------------------------------------- CODE:00401034 CODE:00401034 access_viol_excp: CODE:00401034 lea esi, [ebx+4] CODE:00401037 mov ecx, 4 CODE:0040103C CODE:0040103C loc_40103C: CODE:0040103C lodsd CODE:0040103D add dword ptr [esi-4], 12345678h CODE:00401044 add [ebx+0B0h], eax CODE:0040104A loop loc_40103C CODE:0040104C add dword ptr [ebx+0B8h], 2 CODE:00401053 jmp short loc_401030 CODE:00401055 ; --------------------------------------------------------------------------- CODE:00401055 CODE:00401055 illegal_inst_excp: CODE:00401055 lea edi, [ebx+4] ; debug registers CODE:00401058 mov eax, 0DEADC0DEh CODE:0040105D rol eax, 1 CODE:0040105F stosd ; change dr0 CODE:00401060 rol eax, 1 CODE:00401062 stosd ; change dr1 CODE:00401063 rol eax, 1 CODE:00401065 stosd ; change dr2 CODE:00401066 rol eax, 1 CODE:00401068 stosd ; change dr3 CODE:00401069 and eax, 0 CODE:0040106C stosd ; change dr6 CODE:0040106D add eax, 155h CODE:00401072 stosd ; change dr7 CODE:00401073 add dword ptr [ebx+0B8h], 2 ; change _EIP in _context CODE:0040107A jmp short loc_401030
So our exception handler starts to check the exception code, and it is
programmed to handle ACCESS_VIOLATION_EXCEPTION's and
ILLEGAL_INSTRUCTION_EXCEPTION's Let's look at what happens, when an
illegal instruction exception is being handled (since an illegal
instruction is what brought us here - this time -): So the debug
registers are being set with constants, and finally we disable hardware
breakpoints by setting debug control register to 0x155. The eip value in
the CONTEXT structure is corrected and the exception handler returns.
After we continue with the execution of the crackme, we arrive at
CODE:00401A7D generate_ascii: CODE:00401A7D pusha CODE:00401A7E mov edi, (offset String+50h) CODE:00401A83 xor al, al CODE:00401A85 CODE:00401A85 generate_ascii_loop: CODE:00401A85 stosb CODE:00401A86 inc al CODE:00401A88 test al, al CODE:00401A8A jnz short generate_ascii_loop CODE:00401A8C popa CODE:00401A8D retn
this procedure stores all numbers from 0 to 0xff in the String, after
the last char of the serial (which has a maximunm of 0x28 chars). Next
the length of the username string is calculated:
CODE:00401682 strlen_username: CODE:00401682 popf CODE:00401683 popa CODE:00401684 mov edi, offset String CODE:00401689 repne scasb ... CODE:004016CD mini_mojo4: CODE:004016CD popf CODE:004016CE popa CODE:004016CF not ecx CODE:004016D1 dec ecx ; two's complement -> ecx now holds the correct username's length CODE:004016D2 cmp ecx, 3 CODE:004016D5 jb wrong_length ....
and finally we get to the core of this crackme, the serial generation
procedure:
CODE:00401A8E generate_serial: CODE:00401A8E pusha CODE:00401A8F xor eax, eax CODE:00401A91 mov esi, offset String CODE:00401A96 mov ebx, (offset String+50h) CODE:00401A9B mov edi, (offset String+150h) CODE:00401AA0 pusha CODE:00401AA1 mov ecx, 100h CODE:00401AA6 rep stosb CODE:00401AA8 popa CODE:00401AA9 CODE:00401AA9 loc_401AA9: CODE:00401AA9 lodsb CODE:00401AAA mov edx, ecx CODE:00401AAC imul edx, eax CODE:00401AAF add al, dl CODE:00401AB1 CODE:00401AB1 loc_401AB1: CODE:00401AB1 CODE:00401AB1 xor al, [ebx+ecx] CODE:00401AB4 add [ebx+ecx*4], cl CODE:00401AB7 xor [ebx+eax], cl CODE:00401ABA add al, [ebx+ecx*4] CODE:00401ABD push edx CODE:00401ABE xor edx, edx CODE:00401AC0 mov edx, [edx] CODE:00401AC2 pop edx CODE:00401AC3 cmp al, 41h CODE:00401AC5 jb short loc_401AB1 CODE:00401AC7 cmp al, 5Ah CODE:00401AC9 ja short loc_401AB1 CODE:00401ACB stosb CODE:00401ACC loop loc_401AA9 CODE:00401ACE popa CODE:00401ACF retn
The general idea is that, the username string is going to be read, each
read byte will be changed according to a certain logic, if the resulting
char is not between 0x41 and 0x5A (meaning it's not between 'A' and 'Z')
the calculations are going to take place again. However ...
CODE:00401ABE xor edx, edx CODE:00401AC0 mov edx, [edx] this implies
that exceptions are going to take place during the algorithm,
specifically, illegal access exceptions, so let's look at what our
exception handler behaviour is as far as these exceptions go:
CODE:00401034 access_viol_excp: CODE:00401034 lea esi, [ebx+4] CODE:00401037 mov ecx, 4 CODE:0040103C CODE:0040103C loc_40103C: CODE:0040103C lodsd CODE:0040103D add dword ptr [esi-4], 12345678h CODE:00401044 add [ebx+0B0h], eax ; adds to CONTEXT's eax the starting value in the debug register CODE:0040104A loop loc_40103C CODE:0040104C add dword ptr [ebx+0B8h], 2 CODE:00401053 jmp short loc_401030
What is happening is that whatever is written in the current debug
register is read to eax, the value in the debug register is incremented
by 12345678h, and the value of eax in the CONTEXT structure is
incremented with the earlier value in the debug register. This value is
then used in the generate_serial loop. Finally the value of eip in
CONTEXT is incremented by 2 (40104C). Therefore, when we return from the
exception handler, the next instruction may or may not be a valid
instruction, so another exception may be raised, and the values in the
debug registers reset. In order to emulate this behaviour, since it is
non-linear, and I couldn't find a better way to do it, I re-implemented
the algorithm, with the exception handler included to create the keygen.
When this is done, the entered serial is compared against the calculated
serial, and the number of chars that are equal, must be the same as the
username's length.
I didn't see the created file being used for anything appart from the
handle-check mentioned in the solution, that's why I didn't go into much detail about Mojo1.
Related readings:
http://www.scribd.com/doc/6825346/590BypassHardwareBreakpointProtection
http://vx.netlux.org/lib/vsc04.html#p2
http://www.hexblog.com/2005/12/tracing_exception_handlers.html
http://www.microsoft.com/msj/0197/exception/exception.aspx
The keygen:
The keygen base code was take from one of iczelion's tutorials
CONTROLS.ASM:
.386 .model flat,stdcall option casemap:none ;assume NOTHING include c:\masm32\include\windows.inc include c:\masm32\include\user32.inc include c:\masm32\include\kernel32.inc include c:\masm32\include\masm32.inc includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib includelib c:\masm32\lib\masm32.lib WinMain proto :DWORD,:DWORD,:DWORD,:DWORD Mojo proto :DWORD GenerateASCII proto GenerateSerial proto SetExceptHandler proto ;except_handler proto :EXCEPTION_RECORD,:DWORD,:CONTEXT,:DWORD .data ClassName db "SimpleWinClass",0 AppName db "Our First Window",0 ButtonClassName db "button",0 ButtonText db "My First Button",0 EditClassName db "edit",0 TestString db "Wow! I'm in an edit box now",0 MenuName db "FirstMenu",0 .data? hInstance HINSTANCE ? CommandLine LPSTR ? hwndButton HWND ? hwndEdit1 HWND ? hwndEdit2 HWND ? username db 512 dup(?) serial db 512 dup(?) bigString db 1024 dup(?) .const ButtonID equ 0 EditID1 equ 1 EditID2 equ 2 IDM_HELLO equ 3 IDM_CLEAR equ 4 IDM_GETTEXT equ 5 IDM_EXIT equ 6 .code except_handler: pusha ;lea eax, arg_0 mov eax, ebp add eax, 8 mov eax, [eax] ;lea ebx, arg_8 mov ebx, ebp add ebx, 16 mov ebx, [ebx] cmp dword ptr [eax], 0C000001Dh jz short illegal_inst_excp cmp dword ptr [eax], 0C0000005h jz short access_viol_excp loc_401030: popa xor eax, eax retn access_viol_excp: lea esi, [ebx+4] mov ecx, 4 loc_40103C: lodsd add dword ptr [esi-4], 12345678h add [ebx+0B0h], eax loop loc_40103C add dword ptr [ebx+0B8h], 2 jmp short loc_401030 illegal_inst_excp: lea edi, [ebx+4] mov eax, 0DEADC0DEh rol eax, 1 stosd rol eax, 1 stosd rol eax, 1 stosd rol eax, 1 stosd and eax, 0 stosd add eax, 155h stosd add dword ptr [ebx+0B8h], 2 ; change _EIP in _context (4014DB + 2 = 4014DD) jmp short loc_401030 start: ;##################################### ;invoke SetExceptHandler invoke GetModuleHandle, NULL mov hInstance,eax invoke GetCommandLine mov CommandLine,eax invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT invoke ExitProcess,eax ;##################################### WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD LOCAL wc:WNDCLASSEX LOCAL msg:MSG LOCAL hwnd:HWND mov wc.cbSize,SIZEOF WNDCLASSEX mov wc.style, CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndProc, OFFSET WndProc mov wc.cbClsExtra,NULL mov wc.cbWndExtra,NULL push hInst pop wc.hInstance mov wc.hbrBackground,COLOR_BTNFACE+1 mov wc.lpszMenuName, OFFSET MenuName mov wc.lpszClassName,OFFSET ClassName invoke LoadIcon,NULL,IDI_APPLICATION mov wc.hIcon,eax mov wc.hIconSm,eax invoke LoadCursor,NULL,IDC_ARROW mov wc.hCursor,eax invoke RegisterClassEx, addr wc INVOKE CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\ WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\ CW_USEDEFAULT,300,200,NULL,NULL,\ hInst,NULL mov hwnd,eax INVOKE ShowWindow, hwnd,SW_SHOWNORMAL INVOKE UpdateWindow, hwnd .WHILE TRUE INVOKE GetMessage, ADDR msg,NULL,0,0 .BREAK .IF (!eax) INVOKE TranslateMessage, ADDR msg INVOKE DispatchMessage, ADDR msg .ENDW mov eax,msg.wParam ret WinMain endp WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM .IF uMsg==WM_DESTROY invoke PostQuitMessage,NULL .ELSEIF uMsg==WM_CREATE invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\ WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\ ES_AUTOHSCROLL,\ 50,35,200,25,hWnd,EditID1,hInstance,NULL mov hwndEdit1,eax invoke SetFocus, hwndEdit1 invoke CreateWindowEx, WS_EX_CLIENTEDGE, ADDR EditClassName, NULL,\ WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\ ES_AUTOHSCROLL,\ 50, 70, 200, 25, hWnd, EditID2, hInstance, NULL mov hwndEdit2, eax invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\ WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\ 70,100,140,25,hWnd,ButtonID,hInstance,NULL mov hwndButton,eax .ELSEIF uMsg==WM_COMMAND mov eax,wParam .IF lParam==0 .IF ax==IDM_HELLO invoke SetWindowText,hwndEdit1,ADDR TestString invoke SendMessage,hwndEdit1,WM_KEYDOWN,VK_END,NULL .ELSEIF ax==IDM_CLEAR invoke SetWindowText,hwndEdit1,NULL .ELSEIF ax==IDM_GETTEXT invoke GetWindowText,hwndEdit1,ADDR username,512 invoke MessageBox,NULL,ADDR username,ADDR AppName,MB_OK .ELSE invoke DestroyWindow,hWnd .ENDIF .ELSE .IF ax==ButtonID shr eax,16 .IF ax==BN_CLICKED invoke GetWindowText,hwndEdit1,ADDR bigString,28h invoke Mojo, ADDR username ;invoke SetWindowText,hwndEdit2,ADDR serial invoke SetWindowText,hwndEdit2,ADDR (bigString+150h) .ENDIF .ENDIF .ENDIF .ELSE invoke DefWindowProc,hWnd,uMsg,wParam,lParam ret .ENDIF xor eax,eax ret WndProc endp Mojo proc text:DWORD ;invoke SetExceptHandler ASSUME FS:NOTHING push except_handler push fs:[0] mov fs:[0], esp invoke GenerateASCII ;illegal instruction db 8Dh db 0C0h invoke GenerateSerial ret Mojo endp GenerateASCII proc mov edi, offset bigString+50h xor al, al loop_begin: stosb inc al test al, al jnz loop_begin ret GenerateASCII endp GenerateSerial proc pusha xor eax, eax mov esi, offset bigString ; "" mov ebx, (offset bigString+50h) mov edi, (offset bigString+150h) pusha mov ecx, 100h rep stosb popa ;#####strlen(username) mov edi, offset bigString xor eax, eax or ecx, 0FFFFFFFFh cld repne scasb not ecx dec ecx ;#####strlen(username) mov edi, (offset bigString+150h) loc_401AA9: lodsb mov edx, ecx imul edx, eax add al, dl loc_401AB1: xor al, [ebx+ecx] add [ebx+ecx*4], cl xor [ebx+eax], cl add al, [ebx+ecx*4] push edx xor edx, edx mov edx, [edx] pop edx cmp al, 41h jb short loc_401AB1 cmp al, 5Ah ja short loc_401AB1 stosb loop loc_401AA9 popa retn GenerateSerial endp SetExceptHandler proc ASSUME FS:NOTHING push except_handler push fs:[0] mov fs:[0], esp xor eax, eax retn SetExceptHandler endp end start
CONTORLS.RC:
#define IDM_HELLO 3
#define IDM_CLEAR 4
#define IDM_GETTEXT 5
#define IDM_EXIT 6
FirstMenu MENU
{
POPUP "&Test Controls"
{
MENUITEM "Say Hello",IDM_HELLO
MENUITEM "Clear Edit Box",IDM_CLEAR
MENUITEM "Get Text", IDM_GETTEXT
MENUITEM SEPARATOR
MENUITEM "E&xit",IDM_EXIT
}
}
------------------------
CLAP CLAP CLAP!
ReplyDeleteCongrats for taking your diary one step forward. I must confess I haven't read the whole thing, but it's looking great so far. Not even sure if I should be reading this here, I might eventually someday get to try these so-famous crackmes.
Another thing, blogspot is quite messy to format code, why don't you move your blog to wordpress.com, which has [code][/code] constructs (or similar) allowing you to correctly format the code, thus giving a better preview and readability and increased reader experience?
Hello, sorry for the late answer. I hope that with this syntax highlighter the posts are now a little more perceptible. I will have to mess a little with the width as well.
ReplyDeleteThank you for the feedback, and yes, you should try them, they are great ;)