Getright 4.1.2
Reversing an MFC program with IDA (bye bye Wdasm)
_gK
A little tutorial to whom may interest :)

written by _gK
Well, here should be comments, try to comment yourself coz I'm 2 lazy ; )

There is a crack, a crack in everything That's how the light gets in
Rating
(X)Beginner ( )Intermediate ( )Advanced ( )Expert

For this useful and very nice program I didn't even use SoftIce, but just IDA ver 3.84.
This tutorial is not meant for newbies at their first stage, some IDA knowledge is required.
Getright 4.1.2
Bypassing an easy protection and learning a little IDA at the same time.
Written by _gK


Introduction
When I first decided to crack this little program I had only version 3.3.3.
So I began with this version but as I am 2 lazy I first used wdasm and looked for some good
hardcoded serials in the String References, but found too many!
Therefore I decided to use one randomly choosen, but wait it tells me I'm a pirate!
I uninstalled it and decided to have a go with a newer version, 4.1.2, but it seems it 
remembers I used a blacklisted serial.
So let's crack this elephant's memory protection.


Tools required
To properly disassemble this application you will need IDA.
Infact it heavily relies upon the MFC (Microblowz Foundation Classes, for those who may not know ;).
Any version after 3.84 will do , perhaps even before v3.84 would be good, but you have to manually apply signature
files :(.
Regmon could be of some use too.
A Hex Editor to patch the file.
And of course a resource editor (I used PeBrowse Pro).

Target's URL/FTP
http://www.getright.com
http://www.tucows.com etc.

Program History
Well I noticed that version 3.3.3 used a very similar protection scheme , therefore I may say that
with just some little modification this patch could be easily applied to any version from 3.3.3 to 4.1.2 (and after ;)

Essay
As most of you already know, before cracking a program one must always play a little bit with 
it in order to understand where to begin his cracking/reversing session.
Well after I ran getright I rightclicked on the little icon on the system tray.
Here a popup menu (shortcut menu) is displayed, I chose "About", and pushed the third button
in the dialog box to enter my code.
I wrote in a random number and pushed OK, but a message box tells me "Invalid Registration 
Code...".
Ok let's run IDA and disassemble getright.exe. Well this won't be a tutorial on how to use IDA,
look for them on Fravia's last mirror. Therefore if you know a very little or nothing at all 
about it you'd better read some tutorials on the subject and return here back later;).
After IDA has finished ( it will take about half an hour ), let's look for some interesting 
strings.
Select View menu and choose Names, ALT-T and write "regist" (without quotes, please;).
Remember we are looking for strings, so we will skip all other names but those beginning with 
an "a" (anyway it depends on how you configured strings to be displayed) before the string name.
I only found aRegistrationCode. Hmmm, this could be good, but it is not our message string,
let's double click on the address on its right side anyway.
IDA will bring us to a data section where you will find a typical assembly definition for
strings, I mean:

IDA autogenerated name (that one beginning with an "a")    db   'Real string name',0 

and on its right side some or all Cross References (go to the Options menu, choose "Cross 
References..." and give a number to "Number of xrefs to display").
Well I must admit that as this string is referenced "just" 18 times, I decided to look at the
first cross reference because I didn't know what purpose this string was used for.
Well it is used to keep your registration code in the system registry once registered in HKEY_
CURRENT_USER\Software\HeadLight\GetRight\Config\RegistrationCode.
After some studying, i found out that only 2 references to this key are interesting for our 
purposes.
Infact they are passed to some routines to write some values in the registry. 
Let's see them:
                       (1)                             
0040AC76		 push	 edi                                                                                   
0040AC77		 mov	 dword_0_542F00, 1                                                                     
0040AC81		 call	 sub_0_49CFC6                                                                        
0040AC86		 test	 eax, eax                                                                              
0040AC88		 pop	 ecx                                                                                   
0040AC89		 jz	 short good_guy	 ; see below                                                   
0040AC8B		 push	 offset	unk_0_542E98                                                                   
0040AC90		 mov	 ecx, edi                                                                              
0040AC92		 call	 class CString const & __thiscall CString::operator=(char const *)                     
0040AC97		 push	 offset	unk_0_542E98                                                                   
0040AC9C		 lea	 ecx, [esi+200h]                                                                       
0040ACA2		 call	 void __thiscall CWnd::SetWindowTextA(char const *)                                    
0040ACA7		 push	 7Bh             ; Invalid registration code...                                                                     
0040ACA9		 push	 esi                                                                                   
0040ACAA		 call	 sub_0_48D2B0                                                                          
0040ACAF		 pop	 ecx                                                                                   
0040ACB0		 pop	 ecx                                                                                   
0040ACB1		 jmp	 loc_0_40ADEE                                                                          
0040ACB6 ; ----------------------------------------------------------------------------------                          
0040ACB6                                                                                                               
0040ACB6 good_guy:				 ; CODE	XREF: 0000:0040AC89                                           
0040ACB6		 push	 dword ptr [edi]                                                                       
0040ACB8		 lea	 eax, [ebp-10h]                                                                        
0040ACBB		 push	 offset	"%s"                                                                
0040ACC0		 push	 eax                                                                                   
0040ACC1		 call	 void __cdecl CString::Format(char const *,...)                                        
0040ACC6		 add	 esp, 0Ch                                                                              
0040ACC9		 lea	 ecx, [ebp-10h]
                       (2)                                                                        
0040ACCC		 call	 sub_0_46CF06	 ; modify 0046d406 from	8B45F8 to 33C040                               
0040ACCC					 ; in this way at the test following every                             
0040ACCC					 ; call	to this	routine	you always have	1                              
0040ACCC					 ; and avoid "don't pirate this software..."                                        
0040ACD1		 test	 eax, eax                                                                              
0040ACD3		 jz	 Window00is0?                                                                          
0040ACD9		 push	 ebx             ; ebx = 0, this will disable the window 
                                                 ; whose handle is [esi+188]                                                                       
0040ACDA		 lea	 ecx, [esi+188h]                                                                       
0040ACE0		 call	 int __thiscall CWnd::ShowWindow(int)                                                  
0040ACE5		 push	 ebx                                                                                   
0040ACE6		 lea	 ecx, [esi+200h]                                                                       
0040ACEC		 call	 int __thiscall CWnd::ShowWindow(int)                                                  
0040ACF1		 push	 ebx                                                                                   
0040ACF2		 lea	 ecx, [esi+1C4h]                                                                       
0040ACF8		 call	 int __thiscall CWnd::ShowWindow(int)                                                  
0040ACFD		 push	 ebx                                                                                   
0040ACFE		 lea	 ecx, [esi+98h]                                                                        
0040AD04		 call	 int __thiscall CWnd::ShowWindow(int)                                                  
0040AD09		 push	 5                       ; SW_SHOWDEFAULT                                                              
0040AD0B		 lea	 ecx, [esi+14Ch]                                                                       
0040AD11		 call	 int __thiscall CWnd::ShowWindow(int)                                                  
0040AD16		 mov	 edi, [edi]                                                                            
0040AD18		 call	 class AFX_MODULE_STATE	* __stdcall AfxGetModuleState(void)                            
0040AD1D		 mov	 eax, [eax+4]                                                                          
0040AD20		 push	 edi                                                                                   
0040AD21		 push	 offset	Registrationcode ; here it is our key                                    
0040AD26		 mov	 ecx, eax                                                                              
0040AD28		 push	 dword_0_543098 
                       (3)                                                                       
0040AD2E		 call	 int __thiscall CWinApp::WriteProfileStringA(char const *,char const *,char const *)   
0040AD33		 push	 esi                                                                                   
0040AD34		 lea	 ecx, [ebp-0B0h]                                                                       
0040AD3A		 call	 sub_0_48B8B0                                                                          
0040AD3F		 lea	 ecx, [ebp-0B0h]                                                                       
0040AD45		 mov	 byte ptr [ebp-4], 2                                                                   
0040AD49		 call	 int __thiscall CDialog::DoModal(void)                                                 
0040AD4E		 lea	 ecx, [ebp-54h]                                                                        
0040AD51		 mov	 byte ptr [ebp-4], 3                                                                   
0040AD55		 call	 sub_0_4D3639                                                                          
0040AD5A		 lea	 ecx, [ebp-0B0h]                                                                       
0040AD60		 mov	 byte ptr [ebp-4], 1                                                                   
0040AD64		 call	 sub_0_4C2BFD                                                                          
0040AD69		 jmp	 skip_dont_pirate
                       (4)                                                                         
0040AD6E ; -----------------------------------------------------------------------------------                         
0040AD6E                                                                                                               
0040AD6E Window00is0?:				 ; CODE	XREF: 0000:0040ACD3                                           
0040AD6E		 call	 class AFX_MODULE_STATE	* __stdcall AfxGetModuleState(void)                            
0040AD73		 mov	 eax, [eax+4]                                                                          
0040AD76		 push	 ebx                                                                                   
0040AD77		 push	 offset	Window00 ;  must be 0                                                    
0040AD7C		 mov	 ecx, eax                                                                              
0040AD7E		 push	 dword_0_543098                                                                        
0040AD84		 call	 unsigned int __thiscall CWinApp::GetProfileIntA(char const *,char const *,int)        
0040AD89		 test	 eax, eax                                                                              
0040AD8B		 jnz	 short dont_pirate                                                                    
0040AD8D		 call	 sub_0_4951B5                                                                          
0040AD92		 test	 eax, eax                                                                              
0040AD94		 jz	 short skip_dont_pirate                                                                    
0040AD96                                                                                                               
0040AD96 dont_pirate:				 ; CODE	XREF: 0000:0040AD8B                                          
0040AD96		 push	 1CBh		 ; don't pirate this software                                                     
0040AD9B		 lea	 ecx, [ebp-14h]                                                                        
0040AD9E		 call	 int __thiscall	CString::LoadStringA(unsigned int)                                     
0040ADA3		 push	 dword ptr [ebp-14h]                                                                   
0040ADA6		 lea	 edi, [esi+14Ch]                                                                       
0040ADAC		 mov	 ecx, edi                                                                              
0040ADAE		 call	 void __thiscall CWnd::SetWindowTextA(char const *)                                    
0040ADB3		 push	 5               ; SW_SHOWDEFAULT                                                                          
0040ADB5		 mov	 ecx, edi                                                                              
0040ADB7		 call	 int __thiscall CWnd::ShowWindow(int)                                                  
0040ADBC		 push	 ebx                                                                                   
0040ADBD		 lea	 ecx, [esi+188h]                                                                       
0040ADC3		 call	 int __thiscall CWnd::ShowWindow(int)                                                  
0040ADC8		 lea	 edi, [esi+200h]                                                                       
0040ADCE		 push	 ebx                                                                                   
0040ADCF		 mov	 ecx, edi                                                                              
0040ADD1		 call	 int __thiscall CWnd::ShowWindow(int)                                                  
0040ADD6		 push	 ebx                                                                                   
0040ADD7		 lea	 ecx, [esi+98h]                                                                        
0040ADDD		 call	 int __thiscall CWnd::ShowWindow(int)                                                  
0040ADE2		 push	 offset	unk_0_542E98     ; text to display                                                              
0040ADE7		 mov	 ecx, edi                                                                              
0040ADE9		 call	 void __thiscall CWnd::SetWindowTextA(char const *)                                    
0040ADEE                                                                                                               
0040ADEE skip_dont_pirate:				 ; CODE	XREF: 0000:0040ACB1                                          
0040ADEE					 ; 0000:0040AD69                                                      
0040ADEE					 ; 0000:0040AD94                                                     
0040ADEE		 mov	 dword_0_542F00, ebx                                                                   
0040ADF4                                                                                                               
0040ADF4 loc_0_40ADF4:				 ; CODE	XREF: 0000:0040AC70                                           
0040ADF4		 lea	 ecx, [ebp-14h]                                                                        
0040ADF7		 mov	 [ebp-4], bl                                                                           
0040ADFA		 call	 __thiscall CString::~CString(void)                                                    
0040ADFF		 or	 dword ptr [ebp-4], 0FFFFFFFFh                                                         
0040AE03		 lea	 ecx, [ebp-10h]                                                                        
0040AE06		 call	 __thiscall CString::~CString(void)                                                    
0040AE0B		 mov	 ecx, [ebp-0Ch]                                                                        
0040AE0E		 pop	 edi                                                                                   
0040AE0F		 pop	 esi                                                                                   
0040AE10		 mov	 large fs:0, ecx                                                                       
0040AE17		 pop	 ebx                                                                                   
0040AE18		 leave	                                                                                       
0040AE19		 retn	   

I know I know it's little hard to follow, but I'll try to summarize the more important points:

(1) the call at 0040AC81 is a function (eax, the return value, is tested). The return value
    will establish whether to display the bad_guy message or jump to good_guy.
    We'll patch this to always jump to good_guy.
    The routine beginning at 0049CFC6 is called a second time at 00471C05, and we will patch there
    as well.                                          
(2) This is a function that is repeated all over the file. If it returns 0, you won't be able
    to enter a registration code anymore. It will disable any way to register offline, and in 
    some dialog boxes it will display the annoying "*** Please do not pirate this software ***"
    string. So let's modify this as shown, so that after every test eax will not be equal to 0
    (instead of:
 
    mov eax, dword ptr [ebp-08] 

    we will have:
 
    xor eax, eax 
    inc eax            ).
(3) This function with its counterpartite GetProfileStringA need a little explanation.
    Actually they are not the well known APIs, which share just their names.
    Infact the first function calls RegSetValueExA and RegCloseKey and GetProfileStringA
    calls RegQueryValueExA and RegCloseKey, and they are passed three strings (pointers to 
    char), the first one being the name of the key, the second one is the name of the value 
    (RegistrationCode in this case), the last one is the name of the data (edi = what we 
    entered as registration number).
(4) We come here from point (1) if no patch is applied. Well, this snippet of code verifies, by
    calling GetProfileIntA, if the data at HKCU\Software\HeadLight\GetRight\Config\Window00 is
    equal to 0.
    If it is not you are a pirate. GetProfileIntA is very similar to GetProfileStringA, but its
    last parameter is an integer number, not a string, being the default value assigned to the
    key if this one is not yet present in the registry.
    So that's why if you delete this key at the next run you will have the same key with the 
    same value in the registry!

Well, that's enough for this large piece of code. We still have to patch some bytes in other 
places to make this elephant think it's all sugar what we give it.
Let see where to patch function at 0046CF06:



         sub_0_46CF06
       .
       .
       .
       .
0046D3EB		 cmp	 [ebp+var_1], 0
0046D3EF		 jz	 short loc_0_46D3F5
0046D3F1		 and	 [ebp+var_8], 0  ; zeroes ebp+var_8
0046D3F5 
0046D3F5 loc_0_46D3F5:				 ; CODE	XREF: sub_0_46CF06+4BA
0046D3F5					 ; sub_0_46CF06+4E9
0046D3F5		 push	 edi
0046D3F6		 push	 edi
0046D3F7		 mov	 ecx, ebx
0046D3F9		 call	 sub_0_46D40E
0046D3FE		 test	 eax, eax
0046D400		 jz	 short change_me
0046D402		 and	 [ebp+var_8], 0   ; zeroes ebp+var_8
0046D406 
0046D406 change_me:				 ; CODE	XREF: sub_0_46CF06+4FA
0046D406		 mov	 eax, [ebp+var_8] ; modify this	to 33C040 to always exit
0046D406					  ; with eax different from 0
0046D409		 pop	 esi
0046D40A 
0046D40A loc_0_46D40A:				 ; CODE	XREF: sub_0_46CF06+26
0046D40A		 pop	 edi
0046D40B		 pop	 ebx
0046D40C		 leave	 
0046D40D		 retn	 
0046D40D sub_0_46CF06	 endp

Once edited offset change_me, every call to this function will always return 1. This value is
compared everywhere always in the same way, so that's why we patch this way.

Ok, this is enough to be registered with every registration code ( must be 12 numbers long).
But don't forget that when I installed this version it remembered that I am a pirate (they say
;).
So let's suppose I cannot enter my reg info (it's disabled).
What can I do?
Well the answer is a little above. Do you remember that the value of Window00 is checked against
0?
We have to find where this value is set to something and after a fast search I came to this 
interesting snippet of code:

0049506B 
0049506B ; ------------------- S U B R O U T I N E ---------------------------------------
0049506B 
0049506B 
0049506B sub_0_49506B	 proc near		 ; CODE	XREF: 0000:0041F59E
0049506B					 ; sub_0_46D40E+E2
0049506B					 ; sub_0_46D40E+16F5
0049506B					 ; sub_0_46D40E+19CA
0049506B		 call	 class AFX_MODULE_STATE	* __stdcall AfxGetModuleState(void)
00495070		 mov	 eax, [eax+4]
00495073		 push	 0
00495075		 push	 offset	Registrationcode 
0049507A		 mov	 ecx, eax
0049507C		 push	 dword_0_543098
00495082		 call	 int __thiscall	CWinApp::WriteProfileStringA(char const	*,char const *,char const *)
00495087		 call	 class AFX_MODULE_STATE	* __stdcall AfxGetModuleState(void)
0049508C		 mov	 eax, [eax+4]
0049508F		 push	 1		 ; must	be changed to 0
00495091		 push	 offset	Window00
00495096		 mov	 ecx, eax
00495098		 push	 dword_0_543098
0049509E		 call	 int __thiscall	CWinApp::WriteProfileInt(char const *,char const *,int)
004950A3		 push	 1		 ; must	be changed to 0
004950A5		 push	 offset	ID
004950AA		 push	 dword_0_543148
004950B0		 push	 80000000h
004950B5		 call	 sub_0_49CC5C
004950BA		 add	 esp, 10h
004950BD		 retn	 
004950BD sub_0_49506B	 endp

Changing bytes as shown, you'll never be a pirate, and then you'll need to patch the code to be
registered.
That's all.



Final Notes
Well, I know I wrote too much code, but I love to be as clear as it is needed to understand
not only how and where to patch, but more important than all why.
I promise anyway that in my next tutorial, if any, I'll include less code and more explanations.
For any comment or just to get in touch with me:
gkaizerAThotmail_dot_com


Ob Duh
I won't even bother explaining you that you should BUY this target program if you intend to use it for a longer period than the allowed one. Should you want to STEAL this software instead, you don't need to crack its protection scheme at all: you'll find it on most Warez sites, complete and already regged, farewell, don't come back.




1 All Newbies: Without all of you, the cracking