Special Command—Editing memory with a, eb, ed, ew, eza, ezu

 

When talking about editing memory, we usually think about patching code. Patching code means changing the binary code in memory for, let’s say, when you want to prove a hypothesis while debugging and you don’t have access to the source code.

This is a very exciting subject, and WinDbg has the right tools to do the job. To actually change the memory, we are going to use the following commands:

a [address] – This command assembles instruction mnemonics and puts the resulting instruction codes into memory.

The following commands change the content from a specific memory location:

e{b|d|D|f|p|q|w} <Address> [Values]
e{a|u|za|zu} <Address> < " String " >
e <Address> [Values]

According to WinDbg help file:

e

Enters data in the same format as the most recent e* command. (If the most recent e* command was ea, eza, eu, or ezu, the final parameter will be String and may not be omitted.)

ea

ASCII string (not NULL-terminated).

eb

Byte values.

ed

Double-word values (4 bytes).

eD

Double-precision floating-point numbers (8 bytes).

ef

Single-precision floating-point numbers (4 bytes).

ep

Pointer-sized values. This command is equivalent to ed or eq, depending on whether the target computer's processor architecture is 32-bit or 64-bit, respectively.

eq

Quad-word values (8 bytes).

eu

Unicode string (not NULL-terminated).

ew

Word values (2 bytes).

eza

NULL-terminated ASCII string.

ezu

NULL-terminated Unicode string.

To learn how to edit memory, let’s crack the application below. We will use the Debug version compiled as 32 bits. However, this is just to make things easier because you can use the 64 bits version or Release version. The techniques are the same!

CrackMe application:

// CrackMe.cpp : Defines the entry point for the console application.

//

#include "stdafx.h"

#include <iostream>

using namespace std; // Necessary for cout/cin.

// Declares prototypes.

void AskPassword(void);

bool IsRightPassword(int);

void GiveAccess(void);

void DenyAccess(void);

const int PASSWORD = 357;

void AskPassword()

{

     // User can try to input the password for three times.

     for(int i = 0; i < 3; i++)

     {

           cout << "Tentative " << i + 1 << "/3" << endl;

           cout << "Type the numeric secret password:" << endl;

           int nPassword = 0;

           cin >> nPassword;

           if(IsRightPassword(nPassword))

           {

                GiveAccess();

           break; // User got the right password. Don't need to ask more.

           }

           else

           {

                DenyAccess();

           }

     }

}

void GiveAccess()

{

     cout << "You have access to the system." << endl;

}

void DenyAccess()

{

     cout << "Wrong password!" << endl;

}

inline bool IsRightPassword(int nPasswordToValidate)

{

     return PASSWORD == nPasswordToValidate;

}

int _tmain(int argc, _TCHAR* argv[])

{

     AskPassword();

     return 0;

}

From now on let’s pretend we have never seen the source code before and we don’t have the right password. Let’s use symbols to make things easier, but keep in mind that in real world scenarios you may not have application symbols!

Note: The answers from the tasks below are not meant to be the only right ones. They are just some of many possible answers that can be used to show the commands for memory editing.

Task #1 – Let’s find out the right password.

Run the application from Windbg and break into the debugger when it asks for the password.

Let’s disassemble the main() function:

0:001> uf CrackMe!wmain

*** WARNING: Unable to verify checksum for CrackMe.exe

CrackMe!wmain [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 59]:

   59 013f1c30 55 push ebp

   59 013f1c31 8bec mov ebp,esp

   59 013f1c33 81ecc0000000 sub esp,0C0h

   59 013f1c39 53 push ebx

   59 013f1c3a 56 push esi

   59 013f1c3b 57 push edi

   59 013f1c3c 8dbd40ffffff lea edi,[ebp-0C0h]

   59 013f1c42 b930000000 mov ecx,30h

   59 013f1c47 b8cccccccc mov eax,0CCCCCCCCh

   59 013f1c4c f3ab rep stos dword ptr es:[edi]

   60 013f1c4e e8cbf3ffff call CrackMe!ILT+25(?AskPasswordYAXXZ) (013f101e)

  61 013f1c53 33c0 xor eax,eax

   62 013f1c55 5f pop edi

   62 013f1c56 5e pop esi

   62 013f1c57 5b pop ebx

   62 013f1c58 81c4c0000000 add esp,0C0h

   62 013f1c5e 3bec cmp ebp,esp

   62 013f1c60 e84ef5ffff call CrackMe!ILT+430(__RTC_CheckEsp) (013f11b3)

   62 013f1c65 8be5 mov esp,ebp

   62 013f1c67 5d pop ebp

   62 013f1c68 c3 ret

AskPasswordYAXXZ looks interesting… let’s disassemble it:

0:001> uf 013f101e

CrackMe!AskPassword [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 19]:

   19 013f4190 55 push ebp

   19 013f4191 8bec mov ebp,esp

   19 013f4193 81ecd8000000 sub esp,0D8h

   19 013f4199 53 push ebx

   19 013f419a 56 push esi

   19 013f419b 57 push edi

   19 013f419c 8dbd28ffffff lea edi,[ebp-0D8h]

   19 013f41a2 b936000000 mov ecx,36h

   19 013f41a7 b8cccccccc mov eax,0CCCCCCCCh

   19 013f41ac f3ab rep stos dword ptr es:[edi]

   21 013f41ae c745f800000000 mov dword ptr [ebp-8],0

   21 013f41b5 eb09 jmp CrackMe!AskPassword+0x30 (013f41c0)

CrackMe!AskPassword+0x27 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 21]:

   21 013f41b7 8b45f8 mov eax,dword ptr [ebp-8]

   21 013f41ba 83c001 add eax,1

   21 013f41bd 8945f8 mov dword ptr [ebp-8],eax

CrackMe!AskPassword+0x30 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 21]:

   21 013f41c0 837df803 cmp dword ptr [ebp-8],3

   21 013f41c4 0f8dc2000000 jge CrackMe!AskPassword+0xfc (013f428c)

CrackMe!AskPassword+0x3a [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 23]:

   23 013f41ca 8bf4 mov esi,esp

   23 013f41cc a110a33f01 mov eax,dword ptr [CrackMe!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (013fa310)]

   23 013f41d1 50 push eax

  23 013f41d2 683c783f01 push offset CrackMe!`string' (013f783c)

   23 013f41d7 8b4df8 mov ecx,dword ptr [ebp-8]

   23 013f41da 83c101 add ecx,1

   23 013f41dd 8bfc mov edi,esp

   23 013f41df 51 push ecx

   23 013f41e0 6814783f01 push offset CrackMe!`string' (013f7814)

   23 013f41e5 8b150ca33f01 mov edx,dword ptr [CrackMe!_imp_?coutstd (013fa30c)]

   23 013f41eb 52 push edx

   23 013f41ec e872cfffff call CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (013f1163)

   23 013f41f1 83c408 add esp,8

   23 013f41f4 8bc8 mov ecx,eax

   23 013f41f6 ff1554a33f01 call dword ptr [CrackMe!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01HZ (013fa354)]

   23 013f41fc 3bfc cmp edi,esp

   23 013f41fe e8b0cfffff call CrackMe!ILT+430(__RTC_CheckEsp) (013f11b3)

   23 013f4203 50 push eax

   23 013f4204 e85acfffff call CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (013f1163)

   23 013f4209 83c408 add esp,8

   23 013f420c 8bc8 mov ecx,eax

   23 013f420e ff1508a33f01 call dword ptr [CrackMe!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (013fa308)]

   23 013f4214 3bf4 cmp esi,esp

   23 013f4216 e898cfffff call CrackMe!ILT+430(__RTC_CheckEsp) (013f11b3)

   24 013f421b 8bf4 mov esi,esp

   24 013f421d a110a33f01 mov eax,dword ptr [CrackMe!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (013fa310)]

   24 013f4222 50 push eax

   24 013f4223 68187b3f01 push offset CrackMe!`string' (013f7b18)

   24 013f4228 8b0d0ca33f01 mov ecx,dword ptr [CrackMe!_imp_?coutstd (013fa30c)]

   24 013f422e 51 push ecx

   24 013f422f e82fcfffff call CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (013f1163)

   24 013f4234 83c408 add esp,8

   24 013f4237 8bc8 mov ecx,eax

   24 013f4239 ff1508a33f01 call dword ptr [CrackMe!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (013fa308)]

   24 013f423f 3bf4 cmp esi,esp

   24 013f4241 e86dcfffff call CrackMe!ILT+430(__RTC_CheckEsp) (013f11b3)

   26 013f4246 c745ec00000000 mov dword ptr [ebp-14h],0

   28 013f424d 8bf4 mov esi,esp

   28 013f424f 8d45ec lea eax,[ebp-14h]

   28 013f4252 50 push eax

   28 013f4253 8b0d04a33f01 mov ecx,dword ptr [CrackMe!_imp_?cinstd (013fa304)]

   28 013f4259 ff1500a33f01 call dword ptr [CrackMe!_imp_??5?$basic_istreamDU?$char_traitsDstdstdQAEAAV01AAHZ (013fa300)]

   28 013f425f 3bf4 cmp esi,esp

   28 013f4261 e84dcfffff call CrackMe!ILT+430(__RTC_CheckEsp) (013f11b3)

   30 013f4266 8b45ec mov eax,dword ptr [ebp-14h]

   30 013f4269 50 push eax

   30 013f426a e8eecfffff call CrackMe!ILT+600(?IsRightPasswordYA_NHZ) (013f125d)

   30 013f426f 83c404 add esp,4

   30 013f4272 0fb6c8 movzx ecx,al

   30 013f4275 85c9 test ecx,ecx

   30 013f4277 7409 je CrackMe!AskPassword+0xf2 (013f4282)

CrackMe!AskPassword+0xe9 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 32]:

   32 013f4279 e8e9cfffff call CrackMe!ILT+610(?GiveAccessYAXXZ) (013f1267)

   33 013f427e eb0c jmp CrackMe!AskPassword+0xfc (013f428c)

CrackMe!AskPassword+0xf2 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 37]:

   37 013f4282 e8dbcfffff call CrackMe!ILT+605(?DenyAccessYAXXZ) (013f1262)

   38 013f4287 e92bffffff jmp CrackMe!AskPassword+0x27 (013f41b7)

CrackMe!AskPassword+0xfc [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 41]:

   41 013f428c 52 push edx

   41 013f428d 8bcd mov ecx,ebp

   41 013f428f 50 push eax

   41 013f4290 8d15b4423f01 lea edx,[CrackMe!AskPassword+0x124 (013f42b4)]

   41 013f4296 e819ceffff call CrackMe!ILT+175(_RTC_CheckStackVars (013f10b4)

   41 013f429b 58 pop eax

   41 013f429c 5a pop edx

   41 013f429d 5f pop edi

   41 013f429e 5e pop esi

   41 013f429f 5b pop ebx

   41 013f42a0 81c4d8000000 add esp,0D8h

   41 013f42a6 3bec cmp ebp,esp

   41 013f42a8 e806cfffff call CrackMe!ILT+430(__RTC_CheckEsp) (013f11b3)

   41 013f42ad 8be5 mov esp,ebp

   41 013f42af 5d pop ebp

   41 013f42b0 c3 ret

CrackMe!ILT+25(?AskPasswordYAXXZ):

013f101e e96d310000 jmp CrackMe!AskPassword (013f4190)

After analyzing the code above we see two calls like:

coutstd

And just one call like:

cinstd

This clearly suggests cout and cin from C++ Standard Template Library.

If that is true we know that cin is used to receive information from the user.

Let’s put a breakpoint after the call function just after cin.

0:001> bp 013f425f

0:001> bl

 0 e 013f425f 0001 (0001) 0:**** CrackMe!AskPassword+0xcf

And continue the execution.

We type any number, like 543. Now let’s track our number and see when it is compared against the right password.

At this point the breakpoint is hit.

If you look at the disassembled code again, you will see where our password was stored:

   28 013f424f 8d45ec lea eax,[ebp-14h]

   28 013f4252 50 push eax

   28 013f4253 8b0d04a33f01 mov ecx,dword ptr [CrackMe!_imp_?cinstd (013fa304)]

   28 013f4259 ff1500a33f01 call dword ptr [CrackMe!_imp_??5?$basic_istreamDU?$char_traitsDstdstdQAEAAV01AAHZ (013fa300)]

   28 013f425f 3bf4 cmp esi,esp

   28 013f4261 e84dcfffff call CrackMe!ILT+430(__RTC_CheckEsp) (013f11b3)

   30 013f4266 8b45ec mov eax,dword ptr [ebp-14h]

   30 013f4269 50 push eax

   30 013f426a e8eecfffff call CrackMe!ILT+600(?IsRightPasswordYA_NHZ) (013f125d)

Look at [ebp-14h] . It is a local variable used in cin and used again just before IsRightPassword is called.

If that is true we should get the password we typed:

0:000> dd [ebp-0x14]

001cf9dc 0000021f cccccccc cccccccc 00000000

001cf9ec cccccccc 001cfac4 013f1c53 00000000

001cf9fc 00000000 7efde000 cccccccc cccccccc

001cfa0c cccccccc cccccccc cccccccc cccccccc

001cfa1c cccccccc cccccccc cccccccc cccccccc

001cfa2c cccccccc cccccccc cccccccc cccccccc

001cfa3c cccccccc cccccccc cccccccc cccccccc

001cfa4c cccccccc cccccccc cccccccc cccccccc

0:000> ? 21f

Evaluate expression: 543 = 0000021f

Right! This is the password we just typed. Let’s follow it through the code execution.

It’s being used as argument here:

66 8b45ec mov eax,dword ptr [ebp-14h] ss:002b:001cf9dc=0000021f

013f4269 50 push eax

013f426a e8eecfffff call CrackMe!ILT+600(?IsRightPasswordYA_NHZ) (013f125d)

013f426f 83c404 add esp,4

Note: Use p to step over and t to step into.

After stepping into IsRightPassword() and disassemble it we have:

CrackMe!IsRightPassword:

013f16b0 55 push ebp

013f16b1 8bec mov ebp,esp

013f16b3 81ecc0000000 sub esp,0C0h

013f16b9 53 push ebx

013f16ba 56 push esi

013f16bb 57 push edi

013f16bc 8dbd40ffffff lea edi,[ebp-0C0h]

013f16c2 b930000000 mov ecx,30h

013f16c7 b8cccccccc mov eax,0CCCCCCCCh

013f16cc f3ab rep stos dword ptr es:[edi]

013f16ce 33c0 xor eax,eax

013f16d0 817d0865010000 cmp dword ptr [ebp+8],165h

013f16d7 0f94c0 sete al

013f16da 5f pop edi

013f16db 5e pop esi

013f16dc 5b pop ebx

013f16dd 8be5 mov esp,ebp

013f16df 5d pop ebp

013f16e0 c3 ret

The line at address number 013f16d0 is key. Why? It compares the first function parameter against a specific number.

The parameter happens to be our password, sent by argument as you can see from the disassembled listing. Now let’s see what 165h is in decimal.

Let’s put a breakpoint on address 013f16d0 and continue the execution to that point.

0:000> g

Breakpoint 1 hit

eax=00000000 ebx=7efde000 ecx=00000000 edx=6952daa4 esi=001cf90c edi=001cf900

eip=013f16d0 esp=001cf834 ebp=001cf900 iopl=0 nv up ei pl zr na pe nc

cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246

CrackMe!IsRightPassword+0x20:

013f16d0 817d0865010000 cmp dword ptr [ebp+8],165h ss:002b:001cf908=0000021f

Next:

0:000> dd [ebp+0x8] L1

001cf908 0000021f

Our password, remember?

And:

0:000> ? 165

Evaluate expression: 357 = 00000165

So our password is being compared against 357. If we run the application again and use 357 we can prove that this is the right password.

Mission accomplished!

Task #2 – Let’s make the application use 0 as password.

OK, now we know the right password and we know where the user’s password is being tested against the application’s password. So we just need to change the right password to 0.

Pay attention to the fact that the same password could be used from different parts of the program, so ideally all parts should be changed.

Let’s restart the application and stop the execution when it asks for the password.

After that let’s disassemble CrackMe!IsRightPassword and get the address of the call just before the cmp call. Depending on the Windows version, the address should be different from last time:

0:001> uf CrackMe!IsRightPassword

*** WARNING: Unable to verify checksum for CrackMe.exe

CrackMe!IsRightPassword [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 54]:

   54 00d416b0 55 push ebp

   54 00d416b1 8bec mov ebp,esp

   54 00d416b3 81ecc0000000 sub esp,0C0h

   54 00d416b9 53 push ebx

   54 00d416ba 56 push esi

   54 00d416bb 57 push edi

   54 00d416bc 8dbd40ffffff lea edi,[ebp-0C0h]

   54 00d416c2 b930000000 mov ecx,30h

   54 00d416c7 b8cccccccc mov eax,0CCCCCCCCh

   54 00d416cc f3ab rep stos dword ptr es:[edi]

   55 00d416ce 33c0 xor eax,eax

   55 00d416d0 817d0865010000 cmp dword ptr [ebp+8],165h

   55 00d416d7 0f94c0 sete al

   56 00d416da 5f pop edi

   56 00d416db 5e pop esi

   56 00d416dc 5b pop ebx

   56 00d416dd 8be5 mov esp,ebp

   56 00d416df 5d pop ebp

   56 00d416e0 c3 ret

After hitting the breakpoint at 00d416ce we start the “surgery.”

0:000> a 00d416ce

00d416ce cmp dword ptr [ebp+8], 0

cmp dword ptr [ebp+8], 0

00d416d2

This is the new listing:

0:000> uf CrackMe!IsRightPassword

CrackMe!IsRightPassword [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 54]:

   54 00d416b0 55 push ebp

   54 00d416b1 8bec mov ebp,esp

   54 00d416b3 81ecc0000000 sub esp,0C0h

   54 00d416b9 53 push ebx

   54 00d416ba 56 push esi

   54 00d416bb 57 push edi

   54 00d416bc 8dbd40ffffff lea edi,[ebp-0C0h]

   54 00d416c2 b930000000 mov ecx,30h

   54 00d416c7 b8cccccccc mov eax,0CCCCCCCCh

   54 00d416cc f3ab rep stos dword ptr es:[edi]

   55 00d416ce 837d0800 cmp dword ptr [ebp+8],0

   55 00d416d2 086501 or byte ptr [ebp+1],ah

   55 00d416d5 0000 add byte ptr [eax],al

   55 00d416d7 0f94c0 sete al

   56 00d416da 5f pop edi

   56 00d416db 5e pop esi

   56 00d416dc 5b pop ebx

   56 00d416dd 8be5 mov esp,ebp

   56 00d416df 5d pop ebp

   56 00d416e0 c3 ret

Note that we messed up the function because the original code:

817d0865010000

Has more bytes than the new code has:

837d0800

What do we need to do? Insert NOP instructions that do not do anything just to fill the remaining bytes. We do that using the NOP instruction. You can calculate the number of instructions or see the disassembly after entering each NOP until you see the right continuation according to the original listing.

In our case we use:

a 00d416d2

And enter NOP instructions then hit Enter after that.

You can also use the approach below that uses the code corresponding to the mnemonic:

eb 00d416d2 90 90 90

If you are using the Disassembly Window or if you use uf again, you will be able to see the modified version.

Ours is:

CrackMe!IsRightPassword:

003716b0 55 push ebp

003716b1 8bec mov ebp,esp

003716b3 81ecc0000000 sub esp,0C0h

003716b9 53 push ebx

003716ba 56 push esi

003716bb 57 push edi

003716bc 8dbd40ffffff lea edi,[ebp-0C0h]

003716c2 b930000000 mov ecx,30h

003716c7 b8cccccccc mov eax,0CCCCCCCCh

003716cc f3ab rep stos dword ptr es:[edi]

003716ce 33c0 xor eax,eax

003716d0 837d0800 cmp dword ptr [ebp+8],0

003716d4 90 nop

003716d5 90 nop

003716d6 90 nop

003716d7 0f94c0 sete al

003716da 5f pop edi

003716db 5e pop esi

003716dc 5b pop ebx

003716dd 8be5 mov esp,ebp

003716df 5d pop ebp

003716e0 c3 ret

The original password is 0. Let’s change the user’s password to 0, too:

0:000> dd [ebp+8] L1

002bfaf0 00000003

In our case we used 3.

Let’s change our password to 0, too:

0:000> ed 002bfaf0 0

You can see it was changed:

0:000> dd [ebp+8] L1

002bfaf0 00000000

At this point you should get the message:

“You have access to the system.”

This happens because the application is comparing the user’s password, which is 0 (we changed it), against the original password, which is also 0 (we changed it too).

Using debuggers like OllyDbg or hexadecimal editors, you can go one step further and save another version of the binary, the patched version. That means the application will consider the number 0 as the correct password whenever you run it! But be warned, it is considered a crime to do that.

Task #3 – Let’s remove the test that validates the password.

After running the application again, we break into the debugger when it asks for the password.

0:000> uf CrackMe!wmain

CrackMe!wmain [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 59]:

   59 00ec1c30 55 push ebp

   59 00ec1c31 8bec mov ebp,esp

   59 00ec1c33 81ecc0000000 sub esp,0C0h

   59 00ec1c39 53 push ebx

   59 00ec1c3a 56 push esi

   59 00ec1c3b 57 push edi

   59 00ec1c3c 8dbd40ffffff lea edi,[ebp-0C0h]

   59 00ec1c42 b930000000 mov ecx,30h

   59 00ec1c47 b8cccccccc mov eax,0CCCCCCCCh

   59 00ec1c4c f3ab rep stos dword ptr es:[edi]

   60 00ec1c4e e8cbf3ffff call CrackMe!ILT+25(?AskPasswordYAXXZ) (00ec101e)

   61 00ec1c53 33c0 xor eax,eax

   62 00ec1c55 5f pop edi

   62 00ec1c56 5e pop esi

   62 00ec1c57 5b pop ebx

   62 00ec1c58 81c4c0000000 add esp,0C0h

   62 00ec1c5e 3bec cmp ebp,esp

   62 00ec1c60 e84ef5ffff call CrackMe!ILT+430(__RTC_CheckEsp) (00ec11b3)

   62 00ec1c65 8be5 mov esp,ebp

   62 00ec1c67 5d pop ebp

   62 00ec1c68 c3 ret

0:000> uf 00ec101e

CrackMe!AskPassword [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 19]:

   19 00ec4190 55 push ebp

   19 00ec4191 8bec mov ebp,esp

   19 00ec4193 81ecd8000000 sub esp,0D8h

   19 00ec4199 53 push ebx

   19 00ec419a 56 push esi

   19 00ec419b 57 push edi

   19 00ec419c 8dbd28ffffff lea edi,[ebp-0D8h]

   19 00ec41a2 b936000000 mov ecx,36h

   19 00ec41a7 b8cccccccc mov eax,0CCCCCCCCh

   19 00ec41ac f3ab rep stos dword ptr es:[edi]

   21 00ec41ae c745f800000000 mov dword ptr [ebp-8],0

   21 00ec41b5 eb09 jmp CrackMe!AskPassword+0x30 (00ec41c0)

CrackMe!AskPassword+0x27 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 21]:

   21 00ec41b7 8b45f8 mov eax,dword ptr [ebp-8]

   21 00ec41ba 83c001 add eax,1

   21 00ec41bd 8945f8 mov dword ptr [ebp-8],eax

CrackMe!AskPassword+0x30 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 21]:

   21 00ec41c0 837df803 cmp dword ptr [ebp-8],3

   21 00ec41c4 0f8dc2000000 jge CrackMe!AskPassword+0xfc (00ec428c)

CrackMe!AskPassword+0x3a [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 23]:

   23 00ec41ca 8bf4 mov esi,esp

   23 00ec41cc a110a3ec00 mov eax,dword ptr [CrackMe!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00eca310)]

   23 00ec41d1 50 push eax

   23 00ec41d2 683c78ec00 push offset CrackMe!`string' (00ec783c)

   23 00ec41d7 8b4df8 mov ecx,dword ptr [ebp-8]

   23 00ec41da 83c101 add ecx,1

   23 00ec41dd 8bfc mov edi,esp

   23 00ec41df 51 push ecx

   23 00ec41e0 681478ec00 push offset CrackMe!`string' (00ec7814)

   23 00ec41e5 8b150ca3ec00 mov edx,dword ptr [CrackMe!_imp_?coutstd (00eca30c)]

   23 00ec41eb 52 push edx

   23 00ec41ec e872cfffff call CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00ec1163)

   23 00ec41f1 83c408 add esp,8

   23 00ec41f4 8bc8 mov ecx,eax

   23 00ec41f6 ff1554a3ec00 call dword ptr [CrackMe!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01HZ (00eca354)]

   23 00ec41fc 3bfc cmp edi,esp

   23 00ec41fe e8b0cfffff call CrackMe!ILT+430(__RTC_CheckEsp) (00ec11b3)

   23 00ec4203 50 push eax

   23 00ec4204 e85acfffff call CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00ec1163)

   23 00ec4209 83c408 add esp,8

   23 00ec420c 8bc8 mov ecx,eax

   23 00ec420e ff1508a3ec00 call dword ptr [CrackMe!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (00eca308)]

   23 00ec4214 3bf4 cmp esi,esp

   23 00ec4216 e898cfffff call CrackMe!ILT+430(__RTC_CheckEsp) (00ec11b3)

   24 00ec421b 8bf4 mov esi,esp

   24 00ec421d a110a3ec00 mov eax,dword ptr [CrackMe!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00eca310)]

   24 00ec4222 50 push eax

   24 00ec4223 68187bec00 push offset CrackMe!`string' (00ec7b18)

   24 00ec4228 8b0d0ca3ec00 mov ecx,dword ptr [CrackMe!_imp_?coutstd (00eca30c)]

   24 00ec422e 51 push ecx

   24 00ec422f e82fcfffff call CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00ec1163)

   24 00ec4234 83c408 add esp,8

   24 00ec4237 8bc8 mov ecx,eax

   24 00ec4239 ff1508a3ec00 call dword ptr [CrackMe!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (00eca308)]

   24 00ec423f 3bf4 cmp esi,esp

   24 00ec4241 e86dcfffff call CrackMe!ILT+430(__RTC_CheckEsp) (00ec11b3)

   26 00ec4246 c745ec00000000 mov dword ptr [ebp-14h],0

   28 00ec424d 8bf4 mov esi,esp

   28 00ec424f 8d45ec lea eax,[ebp-14h]

   28 00ec4252 50 push eax

   28 00ec4253 8b0d04a3ec00 mov ecx,dword ptr [CrackMe!_imp_?cinstd (00eca304)]

   28 00ec4259 ff1500a3ec00 call dword ptr [CrackMe!_imp_??5?$basic_istreamDU?$char_traitsDstdstdQAEAAV01AAHZ (00eca300)]

   28 00ec425f 3bf4 cmp esi,esp

   28 00ec4261 e84dcfffff call CrackMe!ILT+430(__RTC_CheckEsp) (00ec11b3)

   30 00ec4266 8b45ec mov eax,dword ptr [ebp-14h]

   30 00ec4269 50 push eax

   30 00ec426a e8eecfffff call CrackMe!ILT+600(?IsRightPasswordYA_NHZ) (00ec125d)

   30 00ec426f 83c404 add esp,4

   30 00ec4272 0fb6c8 movzx ecx,al

   30 00ec4275 85c9 test ecx,ecx

   30 00ec4277 7409 je CrackMe!AskPassword+0xf2 (00ec4282)

CrackMe!AskPassword+0xe9 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 32]:

   32 00ec4279 e8e9cfffff call CrackMe!ILT+610(?GiveAccessYAXXZ) (00ec1267)

   33 00ec427e eb0c jmp CrackMe!AskPassword+0xfc (00ec428c)

CrackMe!AskPassword+0xf2 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 37]:

   37 00ec4282 e8dbcfffff call CrackMe!ILT+605(?DenyAccessYAXXZ) (00ec1262)

   38 00ec4287 e92bffffff jmp CrackMe!AskPassword+0x27 (00ec41b7)

CrackMe!AskPassword+0xfc [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 41]:

   41 00ec428c 52 push edx

   41 00ec428d 8bcd mov ecx,ebp

   41 00ec428f 50 push eax

   41 00ec4290 8d15b442ec00 lea edx,[CrackMe!AskPassword+0x124 (00ec42b4)]

   41 00ec4296 e819ceffff call CrackMe!ILT+175(_RTC_CheckStackVars (00ec10b4)

   41 00ec429b 58 pop eax

   41 00ec429c 5a pop edx

   41 00ec429d 5f pop edi

   41 00ec429e 5e pop esi

   41 00ec429f 5b pop ebx

   41 00ec42a0 81c4d8000000 add esp,0D8h

   41 00ec42a6 3bec cmp ebp,esp

   41 00ec42a8 e806cfffff call CrackMe!ILT+430(__RTC_CheckEsp) (00ec11b3)

   41 00ec42ad 8be5 mov esp,ebp

   41 00ec42af 5d pop ebp

   41 00ec42b0 c3 ret

CrackMe!ILT+25(?AskPasswordYAXXZ):

00ec101e e96d310000 jmp CrackMe!AskPassword (00ec4190)

From above: [ebp-14] holds the user password and is sent as argument to IsRightPassword().

0:000> uf 00ec125d

CrackMe!IsRightPassword [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 54]:

   54 00ec16b0 55 push ebp

   54 00ec16b1 8bec mov ebp,esp

   54 00ec16b3 81ecc0000000 sub esp,0C0h

   54 00ec16b9 53 push ebx

   54 00ec16ba 56 push esi

   54 00ec16bb 57 push edi

   54 00ec16bc 8dbd40ffffff lea edi,[ebp-0C0h]

   54 00ec16c2 b930000000 mov ecx,30h

   54 00ec16c7 b8cccccccc mov eax,0CCCCCCCCh

   54 00ec16cc f3ab rep stos dword ptr es:[edi]

   55 00ec16ce 33c0 xor eax,eax

   55 00ec16d0 817d0865010000 cmp dword ptr [ebp+8],165h

   55 00ec16d7 0f94c0 sete al

   56 00ec16da 5f pop edi

   56 00ec16db 5e pop esi

   56 00ec16dc 5b pop ebx

   56 00ec16dd 8be5 mov esp,ebp

   56 00ec16df 5d pop ebp

   56 00ec16e0 c3 ret

CrackMe!ILT+600(?IsRightPasswordYA_NHZ):

00ec125d e94e040000 jmp CrackMe!IsRightPassword (00ec16b0)

Next step is to replace this:

   55 00ec16ce 33c0 xor eax,eax

   55 00ec16d0 817d0865010000 cmp dword ptr [ebp+8],165h

For this:

55 00ec16ce mov eax, 1

      nop

                   nop

                   …

After the changes:

CrackMe!IsRightPassword:

00ec16b0 55 push ebp

00ec16b1 8bec mov ebp,esp

00ec16b3 81ecc0000000 sub esp,0C0h

00ec16b9 53 push ebx

00ec16ba 56 push esi

00ec16bb 57 push edi

00ec16bc 8dbd40ffffff lea edi,[ebp-0C0h]

00ec16c2 b930000000 mov ecx,30h

00ec16c7 b8cccccccc mov eax,0CCCCCCCCh

00ec16cc f3ab rep stos dword ptr es:[edi]

00ec16ce b801000000 mov eax,1

00ec16d3 650100 add dword ptr gs:[eax],eax

00ec16d6 000f add byte ptr [edi],cl

00ec16d8 94 xchg eax,esp

00ec16d9 c05f5e5b rcr byte ptr [edi+5Eh],5Bh

00ec16dd 8be5 mov esp,ebp

00ec16df 5d pop ebp

00ec16e0 c3 ret

However, notice that we changed all other instructions because our instruction used more bytes than the original instruction.

Let’s fix that using NOPs.

0:000> eb 00ec16d3 90 90 90 90 90 90 90

Another approach is to use:

a 00ec16d3

And type 7 NOP pressing Enter after each one.

The first approach has one key benefit: it can be used from scripts or breakpoints. It’s also faster.

Final code:

CrackMe!IsRightPassword:

00ec16b0 55 push ebp

00ec16b1 8bec mov ebp,esp

00ec16b3 81ecc0000000 sub esp,0C0h

00ec16b9 53 push ebx

00ec16ba 56 push esi

00ec16bb 57 push edi

00ec16bc 8dbd40ffffff lea edi,[ebp-0C0h]

00ec16c2 b930000000 mov ecx,30h

00ec16c7 b8cccccccc mov eax,0CCCCCCCCh

00ec16cc f3ab rep stos dword ptr es:[edi]

00ec16ce b801000000 mov eax,1

00ec16d3 90 nop

00ec16d4 90 nop

00ec16d5 90 nop

00ec16d6 90 nop

00ec16d7 90 nop

00ec16d8 90 nop

00ec16d9 90 nop

00ec16da 5f pop edi

00ec16db 5e pop esi

00ec16dc 5b pop ebx

00ec16dd 8be5 mov esp,ebp

00ec16df 5d pop ebp

00ec16e0 c3 ret

So now the IsRightPassword() function is always return 1 (TRUE).

Use g to continue the execution and from the console window enter any number you want as password.

Task #4 – Let’s make the application call the function that is called when typing the right password even when typing the wrong password.

After running the application and breaking it into the debugger when asking for the password, we start what we call the “pre-surgery” phase.

 

0:000> kL 1000

ChildEBP RetAddr

0046f1ec 75f66f99 kernel32!ReadConsoleInternal+0x15

0046f274 75eeefc6 kernel32!ReadConsoleA+0x40

0046f2bc 67416c3c kernel32!ReadFileImplementation+0x75

0046f350 67416589 MSVCR90D!_read_nolock+0x62c

0046f3a0 673a4453 MSVCR90D!_read+0x219

0046f3c8 673a2748 MSVCR90D!_filbuf+0x113

0046f420 6ce5c8e0 MSVCR90D!fgetc+0x208

0046f430 6ce5c567 MSVCP90D!std::_Fgetc<char>+0x10

0046f518 6ce5c460 MSVCP90D!std::basic_filebuf<char,std::char_traits<char> >::uflow+0xb7

0046f530 6ce58c9a MSVCP90D!std::basic_filebuf<char,std::char_traits<char> >::underflow+0x50

0046f540 6ce59104 MSVCP90D!std::basic_streambuf<char,std::char_traits<char> >::sgetc+0x3a

0046f59c 6ce58c3a MSVCP90D!std::basic_istream<char,std::char_traits<char> >::_Ipfx+0x104

0046f5bc 6ce7eee6 MSVCP90D!std::basic_istream<char,std::char_traits<char> >::sentry::sentry+0x4a

0046f634 0002425f MSVCP90D!std::basic_istream<char,std::char_traits<char> >::operator>>+0x46

0046f724 00021c53 CrackMe!AskPassword+0xcf

0046f7f8 00022598 CrackMe!wmain+0x23

0046f848 000223df CrackMe!__tmainCRTStartup+0x1a8

0046f850 75ec3f39 CrackMe!wmainCRTStartup+0xf

0046f85c 77710409 kernel32!BaseThreadInitThunk+0xe

0046f89c 777103dc ntdll!__RtlUserThreadStart+0x70

0046f8b4 00000000 ntdll!_RtlUserThreadStart+0x1b

AskPassword() is called from main() and looks suspicious. Let’s investigate:

0:000> uf CrackMe!AskPassword

CrackMe!AskPassword [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 19]:

   19 00024190 55 push ebp

   19 00024191 8bec mov ebp,esp

   19 00024193 81ecd8000000 sub esp,0D8h

   19 00024199 53 push ebx

   19 0002419a 56 push esi

   19 0002419b 57 push edi

   19 0002419c 8dbd28ffffff lea edi,[ebp-0D8h]

   19 000241a2 b936000000 mov ecx,36h

   19 000241a7 b8cccccccc mov eax,0CCCCCCCCh

   19 000241ac f3ab rep stos dword ptr es:[edi]

   21 000241ae c745f800000000 mov dword ptr [ebp-8],0

   21 000241b5 eb09 jmp CrackMe!AskPassword+0x30 (000241c0)

CrackMe!AskPassword+0x27 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 21]:

   21 000241b7 8b45f8 mov eax,dword ptr [ebp-8]

   21 000241ba 83c001 add eax,1

   21 000241bd 8945f8 mov dword ptr [ebp-8],eax

CrackMe!AskPassword+0x30 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 21]:

   21 000241c0 837df803 cmp dword ptr [ebp-8],3

   21 000241c4 0f8dc2000000 jge CrackMe!AskPassword+0xfc (0002428c)

CrackMe!AskPassword+0x3a [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 23]:

   23 000241ca 8bf4 mov esi,esp

   23 000241cc a110a30200 mov eax,dword ptr [CrackMe!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (0002a310)]

   23 000241d1 50 push eax

   23 000241d2 683c780200 push offset CrackMe!`string' (0002783c)

   23 000241d7 8b4df8 mov ecx,dword ptr [ebp-8]

   23 000241da 83c101 add ecx,1

   23 000241dd 8bfc mov edi,esp

   23 000241df 51 push ecx

   23 000241e0 6814780200 push offset CrackMe!`string' (00027814)

   23 000241e5 8b150ca30200 mov edx,dword ptr [CrackMe!_imp_?coutstd (0002a30c)]

   23 000241eb 52 push edx

   23 000241ec e872cfffff call CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00021163)

   23 000241f1 83c408 add esp,8

   23 000241f4 8bc8 mov ecx,eax

   23 000241f6 ff1554a30200 call dword ptr [CrackMe!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01HZ (0002a354)]

   23 000241fc 3bfc cmp edi,esp

   23 000241fe e8b0cfffff call CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

   23 00024203 50 push eax

   23 00024204 e85acfffff call CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00021163)

   23 00024209 83c408 add esp,8

   23 0002420c 8bc8 mov ecx,eax

   23 0002420e ff1508a30200 call dword ptr [CrackMe!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (0002a308)]

   23 00024214 3bf4 cmp esi,esp

   23 00024216 e898cfffff call CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

   24 0002421b 8bf4 mov esi,esp

   24 0002421d a110a30200 mov eax,dword ptr [CrackMe!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (0002a310)]

   24 00024222 50 push eax

   24 00024223 68187b0200 push offset CrackMe!`string' (00027b18)

   24 00024228 8b0d0ca30200 mov ecx,dword ptr [CrackMe!_imp_?coutstd (0002a30c)]

   24 0002422e 51 push ecx

   24 0002422f e82fcfffff call CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00021163)

   24 00024234 83c408 add esp,8

   24 00024237 8bc8 mov ecx,eax

   24 00024239 ff1508a30200 call dword ptr [CrackMe!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (0002a308)]

   24 0002423f 3bf4 cmp esi,esp

   24 00024241 e86dcfffff call CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

   26 00024246 c745ec00000000 mov dword ptr [ebp-14h],0

   28 0002424d 8bf4 mov esi,esp

   28 0002424f 8d45ec lea eax,[ebp-14h]

   28 00024252 50 push eax

   28 00024253 8b0d04a30200 mov ecx,dword ptr [CrackMe!_imp_?cinstd (0002a304)]

   28 00024259 ff1500a30200 call dword ptr [CrackMe!_imp_??5?$basic_istreamDU?$char_traitsDstdstdQAEAAV01AAHZ (0002a300)]

   28 0002425f 3bf4 cmp esi,esp

   28 00024261 e84dcfffff call CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

   30 00024266 8b45ec mov eax,dword ptr [ebp-14h]

   30 00024269 50 push eax

   30 0002426a e8eecfffff call CrackMe!ILT+600(?IsRightPasswordYA_NHZ) (0002125d)

   30 0002426f 83c404 add esp,4

   30 00024272 0fb6c8 movzx ecx,al

   30 00024275 85c9 test ecx,ecx

   30 00024277 7409 je CrackMe!AskPassword+0xf2 (00024282)

CrackMe!AskPassword+0xe9 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 32]:

   32 00024279 e8e9cfffff call CrackMe!ILT+610(?GiveAccessYAXXZ) (00021267)

   33 0002427e eb0c jmp CrackMe!AskPassword+0xfc (0002428c)

CrackMe!AskPassword+0xf2 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 37]:

   37 00024282 e8dbcfffff call CrackMe!ILT+605(?DenyAccessYAXXZ) (00021262)

   38 00024287 e92bffffff jmp CrackMe!AskPassword+0x27 (000241b7)

CrackMe!AskPassword+0xfc [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 41]:

   41 0002428c 52 push edx

   41 0002428d 8bcd mov ecx,ebp

   41 0002428f 50 push eax

   41 00024290 8d15b4420200 lea edx,[CrackMe!AskPassword+0x124 (000242b4)]

   41 00024296 e819ceffff call CrackMe!ILT+175(_RTC_CheckStackVars (000210b4)

   41 0002429b 58 pop eax

   41 0002429c 5a pop edx

   41 0002429d 5f pop edi

   41 0002429e 5e pop esi

   41 0002429f 5b pop ebx

   41 000242a0 81c4d8000000 add esp,0D8h

   41 000242a6 3bec cmp ebp,esp

   41 000242a8 e806cfffff call CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

   41 000242ad 8be5 mov esp,ebp

   41 000242af 5d pop ebp

   41 000242b0 c3 ret

At this point it is necessary to analyze what we call “dead listing” in order to get a better understanding of the function and make sure this may be the right function.

In bold above you can see what looks like the routine that checks the password. Remember, we are pretending we don’t know the source code, so to prove the point you should insert breakpoints, debug the application, and see if the DenyAccessYAXXZ above is called when you enter any invalid password.

Ok, so after running the application using breakpoints we prove the point.

However, we don’t know what happens when we enter the right password, but we suppose it is going to call GiveAccessYAXXZ. To prove the point let’s analyze this function.

0:000> uf 00021267

CrackMe!GiveAccess [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 44]:

   44 000215b0 55 push ebp

   44 000215b1 8bec mov ebp,esp

   44 000215b3 81ecc0000000 sub esp,0C0h

   44 000215b9 53 push ebx

   44 000215ba 56 push esi

   44 000215bb 57 push edi

   44 000215bc 8dbd40ffffff lea edi,[ebp-0C0h]

   44 000215c2 b930000000 mov ecx,30h

   44 000215c7 b8cccccccc mov eax,0CCCCCCCCh

   44 000215cc f3ab rep stos dword ptr es:[edi]

   45 000215ce 8bf4 mov esi,esp

   45 000215d0 a110a30200 mov eax,dword ptr [CrackMe!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (0002a310)]

   45 000215d5 50 push eax

   45 000215d6 6840780200 push offset CrackMe!`string' (00027840)

   45 000215db 8b0d0ca30200 mov ecx,dword ptr [CrackMe!_imp_?coutstd (0002a30c)]

   45 000215e1 51 push ecx

   45 000215e2 e87cfbffff call CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00021163)

   45 000215e7 83c408 add esp,8

   45 000215ea 8bc8 mov ecx,eax

   45 000215ec ff1508a30200 call dword ptr [CrackMe!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (0002a308)]

   45 000215f2 3bf4 cmp esi,esp

   45 000215f4 e8bafbffff call CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

   46 000215f9 5f pop edi

   46 000215fa 5e pop esi

   46 000215fb 5b pop ebx

   46 000215fc 81c4c0000000 add esp,0C0h

   46 00021602 3bec cmp ebp,esp

   46 00021604 e8aafbffff call CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

   46 00021609 8be5 mov esp,ebp

   46 0002160b 5d pop ebp

   46 0002160c c3 ret

CrackMe!ILT+610(?GiveAccessYAXXZ):

00021267 e944030000 jmp CrackMe!GiveAccess (000215b0)

After reviewing the code we located one string. Let’s examine that:

0:000> db 00027840

00027840 59 6f 75 20 68 61 76 65-20 61 63 63 65 73 73 20 You have access

00027850 74 6f 20 74 68 65 20 73-79 73 74 65 6d 2e 00 00 to the system...

00027860 66 00 3a 00 5c 00 64 00-64 00 5c 00 76 00 63 00 f.:.\.d.d.\.v.c.

00027870 74 00 6f 00 6f 00 6c 00-73 00 5c 00 63 00 72 00 t.o.o.l.s.\.c.r.

00027880 74 00 5f 00 62 00 6c 00-64 00 5c 00 73 00 65 00 t._.b.l.d.\.s.e.

00027890 6c 00 66 00 5f 00 78 00-38 00 36 00 5c 00 63 00 l.f._.x.8.6.\.c.

000278a0 72 00 74 00 5c 00 73 00-72 00 63 00 5c 00 63 00 r.t.\.s.r.c.\.c.

000278b0 72 00 74 00 65 00 78 00-65 00 2e 00 63 00 00 00 r.t.e.x.e...c...

Excellent! This is the right function. The string is an ANSI string, not Unicode. A Unicode string should have two bytes for each character.

Here is another way to see that:

0:000> da 00027840

00027840 "You have access to the system."

Let’s see the two calls, for right and wrong passwords:

0:000> uf /c CrackMe!AskPassword

CrackMe!AskPassword (00024190) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 19]

  CrackMe!AskPassword+0x5c (000241ec) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 23]:

    call to CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00021163)

  CrackMe!AskPassword+0x66 (000241f6) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 23]:

    call to MSVCP90D!std::basic_ostream<char,std::char_traits<char> >::operator<< (6ce7a520) 

  CrackMe!AskPassword+0x6e (000241fe) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 23]:

    call to CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

  CrackMe!AskPassword+0x74 (00024204) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 23]:

    call to CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00021163)

  CrackMe!AskPassword+0x7e (0002420e) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 23]:

    call to MSVCP90D!std::basic_ostream<char,std::char_traits<char> >::operator<< (6ce79f60) 

  CrackMe!AskPassword+0x86 (00024216) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 23]:

    call to CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

  CrackMe!AskPassword+0x9f (0002422f) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 24]:

    call to CrackMe!ILT+350(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00021163)

  CrackMe!AskPassword+0xa9 (00024239) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 24]:

    call to MSVCP90D!std::basic_ostream<char,std::char_traits<char> >::operator<< (6ce79f60)

  CrackMe!AskPassword+0xb1 (00024241) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 24]:

    call to CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

  CrackMe!AskPassword+0xc9 (00024259) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 28]:

    call to MSVCP90D!std::basic_istream<char,std::char_traits<char> >::operator>> (6ce7eea0)

  CrackMe!AskPassword+0xd1 (00024261) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 28]:

    call to CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

  CrackMe!AskPassword+0xda (0002426a) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 30]:

    call to CrackMe!ILT+600(?IsRightPasswordYA_NHZ) (0002125d)

  CrackMe!AskPassword+0xe9 (00024279) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 32]:

    call to CrackMe!ILT+610(?GiveAccessYAXXZ) (00021267)

  CrackMe!AskPassword+0xf2 (00024282) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 37]:

    call to CrackMe!ILT+605(?DenyAccessYAXXZ) (00021262)

  CrackMe!AskPassword+0x106 (00024296) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 41]:

    call to CrackMe!ILT+175(_RTC_CheckStackVars (000210b4)

  CrackMe!AskPassword+0x118 (000242a8) [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 41]:

    call to CrackMe!ILT+430(__RTC_CheckEsp) (000211b3)

Hopefully the number of bytes is the same:

CrackMe!AskPassword+0xe9 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 32]:

   32 00024279 e8e9cfffff call CrackMe!ILT+610(?GiveAccessYAXXZ) (00021267)

   33 0002427e eb0c jmp CrackMe!AskPassword+0xfc (0002428c)

CrackMe!AskPassword+0xf2 [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 37]:

   37 00024282 e8dbcfffff call CrackMe!ILT+605(?DenyAccessYAXXZ) (00021262)

We are ready to start the “surgery”:

0:000> u 00021267

CrackMe!ILT+610(?GiveAccessYAXXZ):

00021267 e944030000 jmp CrackMe!GiveAccess (000215b0)

See the indirection? We need 000215b0.

0:000> u 000215b0

CrackMe!GiveAccess [c:\development\my tools\book\crackme\crackme\crackme.cpp @ 44]:

000215b0 55 push ebp

000215b1 8bec mov ebp,esp

000215b3 81ecc0000000 sub esp,0C0h

000215b9 53 push ebx

000215ba 56 push esi

000215bb 57 push edi

000215bc 8dbd40ffffff lea edi,[ebp-0C0h]

000215c2 b930000000 mov ecx,30h

0:000> a 00024282

00024282 call CrackMe!GiveAccess

call CrackMe!GiveAccess

00024287

New listing:

00024277 7409 je CrackMe!AskPassword+0xf2 (00024282)

00024279 e8e9cfffff call CrackMe!ILT+610(?GiveAccessYAXXZ) (00021267)

0002427e eb0c jmp CrackMe!AskPassword+0xfc (0002428c)

00024280 eb05 jmp CrackMe!AskPassword+0xf7 (00024287)

00024282 e829d3ffff call CrackMe!GiveAccess (000215b0)

00024287 e92bffffff jmp CrackMe!AskPassword+0x27 (000241b7)

0002428c 52 push edx

0002428d 8bcd mov ecx,ebp

0002428f 50 push eax

Now if you type “g” and continue the execution entering any invalid password the application is going to show the message that says you have access to the system.

However, the application is going to ask you the password again because you typed the wrong password. In other words, after changing the application according to the instructions above, it will call the function that is supposed to be called only if you type the right password! ;-)

Here is a fun demonstration for Windows XP on 32 bits: https://blogs.msdn.com/debuggingtoolbox/archive/2007/03/28/windbg-script-playing-with-minesweeper.aspx

 

Another related blog article:

https://blogs.msdn.com/debuggingtoolbox/archive/2007/04/27/windbg-script-tracing-messagebox-calls.aspx

 

For more WinDbg commands check the Special Commands section in this blog.