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:
For more WinDbg commands check the Special Commands section in this blog.