Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 11

Cracking Delphi Programs

By CodeRipper
Tools used: DeDe by DaFixer, Olly debugger, PE Explorer,
De Decompiler Lite

I. Let you familiarize with Delphi:


A form is a class which contain a lot of buttons, radiobutons etc.
So if we have a form called TfrmPurchase we can have a lot of properties/events:
TfrmPurchase.btnOKClick called when we click OK
TfrmPurchase.btnCancelClick - called when we click Cancel
TfrmPurchase.FormCreate is called when the form is created; default when you double click
on Form
TfrmPurchase.FormShow - is called when the form is showed
TfrmPurchase.TimerTimer is called when the timer is out (something like WM_TIMER
from VISUAL C++)
TfrmPurchase.Edit1Change - called when the contents of Edit1 is changed
TfrmPurchase.Memo1Change - called when the contents of Memo1 is changed
If we have on the body of TForm1.Button1Click (under Nag Form.exe):
Form1.DestroyWindowHandle; // kill Form1
Form2.ShowModal; // show the Form2
Form3.ShowModal; // show the Form3
The code will look like this:
0045241F MOV EAX,DWORD PTR DS:[455B74] ; reference to Form1 (under Class
Information the BSS value)
00452424 MOV EDX,DWORD PTR DS:[EAX] ; now edx contain VMT Ptr (Classes Info
in DeDe)
00452426 CALL DWORD PTR DS:[EDX+B4]
0045242C MOV EAX,DWORD PTR DS:[454378] ; reference to TForm2 instance (DATA)
00452431 MOV EAX,DWORD PTR DS:[EAX] ; now eax contains the HEAP value
00452433 MOV EDX,DWORD PTR DS:[EAX] ; now edx contain VMT Ptr
00452435 CALL DWORD PTR DS:[EDX+F8]
0045243B MOV EAX,DWORD PTR DS:[454220] ; reference to TForm2 instance
; (DATA)
00452440 MOV EAX,DWORD PTR DS:[EAX]
00452442 MOV EDX,DWORD PTR DS:[EAX]
00452444 CALL DWORD PTR DS:[EDX+F8]
For finding these values you must go at Classes Info (in DeDe), double click
on the wanted form and look on the right part you will see DATA,BSS,HEAP.
A class is an abstract structure witch contains methods and variables (properties).
An object is an instance of one class, a materialization of a class.
Objects are kept in a special memory called HEAP.

Delphi use for parsing parameters to functions EAX, EDX, ECX, if they are more then 3
parameters will be used the stack (push parameter_4, push parameter_5). Note that these
parameters are passed in reverse order.
Delphi deals with global and local variables reference it on the following way:
- [ebp+value] means that is pointer to a global variable
- [ebp-value] means that it is pointer to a local variable
Example:
00484A6C 8B45FC mov eax, [ebp-$04] ; pointer to a local variable in eax
00484A6F E830F1F7FF call 00403BA4 ; call System.LStrOfChar()

II. How a Delphi program looks at entry point:


The code of program:
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1); the NAG form which is first created
Application.CreateForm(TForm2, Form2);
Application.CreateForm(TForm3, Form3);
Application.Run;
end.
The compiled code will be:
00452668 PUSH EBP
00452669 MOV EBP,ESP
0045266B ADD ESP,-10
0045266E MOV EAX,004524C0
00452673 CALL .00405C94 ; this is the _InitExe routine that also initialize units
00452678 MOV EAX,DWORD PTR DS:[454260] ; TApplication instance (Classes Info)
0045267D MOV EAX,DWORD PTR DS:[EAX]
0045267F CALL .00450578 ; Forms.TApplication.Initialize()
00452684 MOV ECX,DWORD PTR DS:[454344] ; for killing the Form1 we must change
; this to jmp 0045269C
; You should notice that the first form which is created is considerate here as being the
main form
0045268A MOV EAX,DWORD PTR DS:[454260]
0045268F MOV EAX,DWORD PTR DS:[EAX]
00452691 MOV EDX,DWORD PTR DS:[452274]
00452697 CALL .00450590 ; Application.CreateForm(TForm1, Form1);
0045269C MOV ECX,DWORD PTR DS:[454378]
004526A2 MOV EAX,DWORD PTR DS:[454260]
004526A7 MOV EAX,DWORD PTR DS:[EAX]
004526A9 MOV EDX,DWORD PTR DS:[451F04]
004526AF CALL .00450590 ; Application.CreateForm(TForm2, Form2);
004526B4 MOV ECX,DWORD PTR DS:[454220]
004526BA MOV EAX,DWORD PTR DS:[454260]
004526BF MOV EAX,DWORD PTR DS:[EAX]
004526C1 MOV EDX,DWORD PTR DS:[4520C8]
004526C7 CALL .00450590 ; Application.CreateForm(TForm3, Form3);
004526CC MOV EAX,DWORD PTR DS:[454260]

004526D1 MOV EAX,DWORD PTR DS:[EAX]


004526D3 CALL .00450610 ; Application.Run;
004526D8 CALL .00403DC8 ; close the application (call ExitProcess)
_InitExe - Initialization of units means running its initialization code.
So you must step into 00405C94 and trace until you reach the IniUnits() routine.
If you enter under 00405C94 you will see a GetModuleHandleA, after that is a call in which
you must enter, after you enter inside him you will see another one -> step over this call whit
F8 and return (RETN), you will see another call -> this time step into this call and you will
find:
00403C1C MOV DWORD PTR DS:[455014],JMP.&kernel32.RaiseException
00403C26 MOV DWORD PTR DS:[455018],JMP.&kernel32.RtlUnwind
00403C30 MOV DWORD PTR DS:[45563C],EAX
00403C35 XOR EAX,EAX
00403C37 MOV DWORD PTR DS:[455640],EAX
00403C3C MOV DWORD PTR DS:[455644],EDX
00403C42 MOV EAX,DWORD PTR DS:[EDX+4]
00403C45 MOV DWORD PTR DS:[45502C],EAX
00403C4A CALL .00403B08
00403C4F MOV BYTE PTR DS:[455034],0
00403C56 CALL .00403BB4 ; you must trace into inside this one
00403C5B RETN
If you enter inside call 00403BB4 you will find:

00403BDC CMP EDI,EBX


00403BDE JLE SHORT .00403BF7
00403BE0 MOV EAX,DWORD PTR SS:[EBP-4]
00403BE3 MOV ESI,DWORD PTR DS:[EAX+EBX*8] ; prepare the offset of initialization
; routine of a unit
00403BE6 INC EBX ; increase processed units counter
00403BE7 MOV DWORD PTR DS:[455640],EBX
00403BED TEST ESI,ESI ; is there any initialization routine for this unit?
00403BEF JE SHORT .00403BF3 ; if no, then process next unit
00403BF1 CALL ESI ; else call it!
00403BF3 CMP EDI,EBX ; did we processed all units?
00403BF5 JG SHORT .00403BE0 ; if no go back
You can get a list whit all units from the program:
Open the exe file with PE Explorer and go to Resource Viewer/Editor; double click on RC
Data and click to PACKAGEINFO and you will see a list with all units from the program.

How we can simply find the offset of a method:


Load CrackMe#3.exe in Resource Tuner or PE Explorer and go at RC Data.
TFORM1 has two buttons Button1 and Button2, Button1 has the event OnClick
Button1Click and Button2 has the event OnClick Button2Click.

Also we have a menu called MainMenu1 a submenu called Help1 and the menu item is called
About1 -> About1 has the event OnClick About1Click.
In the case of an Editbox we could also have the event OnChange Edit1Change (called when
the text from Edit1 is changed).
Next step:
We load the file under a hexeditor and we search for the ASCII string "Button1Click":
000531C0
000531D0
000531E0
000531F0

07 42 75 74 74 6F 6E 31
61 62 65 6C 31 F8 02 00
6C 32 01 00 13 00 28 3E
6E 31 43 6C 69 63 6B 05

F4 02 00 00 01 00 06 4C
00 01 00 06 4C 61 62 65
45 00 0C 42 75 74 74 6F
54 47 6F 6F 64 02 00 60

.Button1......L
abel1......Labe
l2....(>E..Butto
n1Click.TGood..

The red value before the finded string represents the address of methods called when you
click "Button1": 00453E28
Similar in the case of About1 we have 00454814.
Similar in the case of Label3Click we have 00454824.

How we can easily find the code executed when you press a button or a
menu items
Purpose of this: You got the code called when you click a menu item and we want to find the
address which is called when you click on any menu item!
Same things works for a Visual C++ program which use MFC42.DLL.
1. In the case of labels/buttons:
We set a breakpoint to 00454824, we click on Label3 and after we return from 00454824 we
find:
0043248E TEST BYTE PTR DS:[EBX+1C],10
00432492 JNZ SHORT CrackMe#.004324A6
00432494 CMP DWORD PTR DS:[EBX+6C],0
00432498 JE SHORT CrackMe#.004324A6
0043249A MOV EDX,EBX
0043249C MOV EAX,DWORD PTR DS:[EBX+6C]
0043249F MOV ECX,DWORD PTR DS:[EAX]
004324A1 CALL DWORD PTR DS:[ECX+18]
004324A4 JMP SHORT CrackMe#.004324BE
004324A6 CMP WORD PTR DS:[EBX+122],0
004324AE JE SHORT CrackMe#.004324BE
004324B0 MOV EDX,EBX
004324B2 MOV EAX,DWORD PTR DS:[EBX+124]
004324B8 CALL DWORD PTR DS:[EBX+120] ; this one calls the method 00454824
004324BE POP EBX ; we are here
004324BF RETN

The address 004324B8 is called in the case of all buttons and all of labels, just set a
breakpoint on it.
2. In the case of menu items:
We set a breakpoint to 00454814, we click on About and after we return from 00454814 we
find:
00442791 MOV EAX,DWORD PTR DS:[EAX+40]
00442794 CMP EAX,DWORD PTR DS:[EBX+88]
0044279A JE SHORT CrackMe#.004427AC
0044279C MOV EDX,EBX
0044279E MOV EAX,DWORD PTR DS:[EBX+8C]
004427A4 CALL DWORD PTR DS:[EBX+88]
004427AA JMP SHORT CrackMe#.004427DC
004427AC TEST BYTE PTR DS:[EBX+1C],10
004427B0 JNZ SHORT CrackMe#.004427C4
004427B2 CMP DWORD PTR DS:[EBX+44],0
004427B6 JE SHORT CrackMe#.004427C4
004427B8 MOV EDX,EBX
004427BA MOV EAX,DWORD PTR DS:[EBX+44]
004427BD MOV ECX,DWORD PTR DS:[EAX]
004427BF CALL DWORD PTR DS:[ECX+18]
004427C2 JMP SHORT CrackMe#.004427DC
004427C4 CMP WORD PTR DS:[EBX+8A],0
004427CC JE SHORT CrackMe#.004427DC
004427CE MOV EDX,EBX
004427D0 MOV EAX,DWORD PTR DS:[EBX+8C]
004427D6 CALL DWORD PTR DS:[EBX+88] ; this one calls the method 00454814
004427DC POP ESI ; we are here
004427DD POP EBX
004427DE RETN
The address 004427D6 is called in the case of all buttons and all of menu items, just set a
breakpoint on it.

Disable a menu item:


EnableMenuItem api is sometimes used to disable a menu item:
0012F074
0012F078
0012F07C
0012F080

0044C24A CALL to EnableMenuItem from CrackMe#.0044C245


002E0598 hMenu = 002E0598
0000F020 ItemID = F020 (61472.)
00000001 Flags = MF_BYCOMMAND|MF_GRAYED|MF_STRING

Also can be used AppendMenuA or AppendMenuW:


BOOL AppendMenu(
HMENU hMenu,
UINT uFlags,

UINT_PTR uIDNewItem,
LPCTSTR lpNewItem
);
If the uFlags is 1 the menu item will be disabled, if uFlags is 0 the menu item will be enabled!

I. Killing NAG FORMS


Do he ReleaseCapture on Olly (ReleaseCapture is from user32.dll) under same way can
be also used for MessageDlg/ShowMessage
You should see something like this:
0045306D MOV DL,1
0045306F MOV EAX,DWORD PTR DS:[410458]
00453074 CALL HelpMan_.0040CB8C
00453079 CALL HelpMan_.004037B0
0045307E CALL JMP.&user32.GetCapture
00453083 TEST EAX,EAX
00453085 JE SHORT HelpMan_.00453098
00453087 PUSH 0
; lParam = 0
00453089 PUSH 0
; wParam = 0
0045308B PUSH 1F
; Message = WM_CANCELMODE
0045308D CALL JMP &user32.GetCapture
00453092 PUSH EAX
; hWnd
00453093 CALL JMP.&user32.SendMessageA
00453098 CALL JMP.&user32.ReleaseCapture
0045309D MOV EAX,DWORD PTR SS:[EBP-4] ; ReleaseCapture return to this
004530A0 OR BYTE PTR DS:[EAX+2CC],8
004530A7 CALL JMP.&user32.GetActiveWindow
Delete the hardware breakpoint and set a hardware breakpoint to last ret and Run with F9.
Press Continue on form.
You should now break to last ret.
Now we step over with F8 a lot of times until we see something like this:
006A0349 MOV EAX,DWORD PTR DS:[6AB3EC]
006A034E MOV EAX,DWORD PTR DS:[EAX]
006A0350 MOV EDX,DWORD PTR DS:[EAX]
006A0352 CALL DWORD PTR DS:[EDX+D8] ; this create the form which could be
a nasty NAG - nop him and you will kill the NAG!
006A0358 MOV EAX,DWORD PTR DS:[6AB76C] ; we land here
A strange way to kill the NAG:
For some NAGS replace at 006A0352 with the method called when you click Try or Continue
( example: call TReminderForm.TryButtonClick) and now the beach always starts without
NAG!

II. Killing hardest NAGS:


For some nags first way (replaing the NAG creation whit nop) wont work so here is the
second way of doing it.
Do he ReleaseCapture on Olly (ReleaseCapture is from user32.dll)
You will now break to user32 code, return from it and you will see: (this is common to all
Delphi functions):
00492477
MOV DL,1
00492479
MOV EAX,DWORD PTR DS:[419F78]
0049247E CALL scrwon.0040E2A0
00492483
CALL scrwon.0040427C
00492488
CALL scrwon.00407680 ; JMP to USER32.GetCapture
0049248D TEST EAX,EAX
0049248F
JE SHORT scrwon.004924A2
00492491
PUSH 0
00492493
PUSH 0
00492495
PUSH 1F
00492497
CALL scrwon.00407680 ; JMP to USER32.GetCapture
0049249C
PUSH EAX
0049249D
CALL scrwon.004079A0 ; JMP to USER32.SendMessageA
004924A2 CALL scrwon.00407960 ; JMP to USER32.ReleaseCapture
004924A7 MOV EAX,DWORD PTR DS:[5CCBF0] ; we land here
004924AC CALL scrwon.0049535C
004924B1
XOR EAX,EAX
004924B3
PUSH EBP
004924B4
PUSH scrwon.004926D5
004924B9
PUSH DWORD PTR FS:[EAX]
004924BC
MOV DWORD PTR FS:[EAX],ESP
004924BF
MOV EAX,DWORD PTR SS:[EBP-4]
004924C2
OR BYTE PTR DS:[EAX+2F4],8
004924C9
CALL scrwon.00407670 ; JMP to USER32.GetActiveWindow
Delete the hardware breakpoint and set a hardware breakpoint to the last ret from code and
Run with F9.
Press Continue on form.
You should now break at last ret.
Now step over with F8 until we see something like:
005BFAB9 MOV EDX,DWORD PTR DS:[5CBC24]
005BFABF MOV DWORD PTR DS:[EDX],EAX
005BFAC1 MOV EAX,DWORD PTR DS:[5CBC24]
005BFAC6 MOV EAX,DWORD PTR DS:[EAX]
005BFAC8 MOV EDX,DWORD PTR DS:[EAX]
005BFACA CALL DWORD PTR DS:[EDX+EC] ; this create the code
005BFAD0 MOV EAX,DWORD PTR DS:[5CBC24] ; we land here
Now restart the application and set hardware breakpoint on execute to 005BFACA.
You should now break to 005BFACA step into this call and you will see:
..
0049252B PUSH EBP
0049252C PUSH scrwon.004926B3

00492531
00492534
00492537
0049253A
0049253F
00492541
00492542
00492547
0049254A
0049254D
0049254F
00492551
00492556
00492559
0049255E
0049255F
00492564
00492567
00492569
0049256F
00492574
00492579
0049257E
00492585
00492587
0049258A
00492594
00492596
00492599
004925A0
004925A2
004925A5
004925AA
004925AD
004925B4

PUSH DWORD PTR FS:[EAX]


MOV DWORD PTR FS:[EAX],ESP
MOV EAX,DWORD PTR SS:[EBP-4]
CALL scrwon.00492350
XOR EAX,EAX
PUSH EBP
PUSH scrwon.00492607
PUSH DWORD PTR FS:[EAX]
MOV DWORD PTR FS:[EAX],ESP
PUSH 0
PUSH 0
PUSH 0B000
MOV EAX,DWORD PTR SS:[EBP-4]
CALL scrwon.00476A8C
PUSH EAX
CALL scrwon.004079A0 ; JMP to USER32.SendMessageA
MOV EAX,DWORD PTR SS:[EBP-4]
XOR EDX,EDX
MOV DWORD PTR DS:[EAX+24C],EDX
MOV EAX,DWORD PTR DS:[5CCBF0]
CALL scrwon.004964D8
MOV EAX,DWORD PTR DS:[5CCBF0]
CMP BYTE PTR DS:[EAX+9C],0
JE SHORT scrwon.00492596
(74 04)
MOV EAX,DWORD PTR SS:[EBP-4]
MOV DWORD PTR DS:[EAX+24C],2
JMP SHORT scrwon.004925AA
MOV EAX,DWORD PTR SS:[EBP-4]
CMP DWORD PTR DS:[EAX+24C],0
JE SHORT scrwon.004925AA
MOV EAX,DWORD PTR SS:[EBP-4]
CALL scrwon.004922A4
MOV EAX,DWORD PTR SS:[EBP-4]
CMP DWORD PTR DS:[EAX+24C],0
JE SHORT scrwon.0049256F

This code is a loop which wait for user to press a button, if button Continue is pressed the je
from 00492585 will jump and the application will actually run.
But this code is used for all forms of application and if you change the je forever you will
have a bug.
So we must change code at 005BFACA to jump to our code cave.
In our code cave we enter:
MOV BYTE PTR [00492585],075 ; change je to jne
CALL DWORD PTR DS:[EDX+0EC] ; call the changed code
MOV BYTE PTR [00492585],074 ; we restore back to je
JMP 005BFAD0 ; jump right after NAG creation
The problem:
The NAG is still showed for some seconds.
I tried to find a way to set a form invisible butt I couldnt do.

Form1.Hide;
Form2.Show;
Form3.Show;
get translated into:
0045103C MOV EAX,DWORD PTR DS:[454B74]
00451041 CALL Project1.0044B808 ; Form1.Hide
00451046 MOV EAX,DWORD PTR DS:[453358]
0045104B MOV EAX,DWORD PTR DS:[EAX]
0045104D CALL HideForm.0044B810 ; Form2.Show
00451052 MOV EAX,DWORD PTR DS:[453200]
00451057 MOV EAX,DWORD PTR DS:[EAX]
00451059 CALL Project1.0044B810 ; Form3.Show
Under Form1.Hide you will see:
0044B808 XOR EDX,EDX
0044B80A CALL .00447BBC
0044B80F RETN
Under Form2.Show/ Form3.Show you will see:
0044B810 PUSH EBX
0044B811 MOV EBX,EAX
0044B813 MOV DL,1
0044B815 MOV EAX,EBX
0044B817 CALL HideForm.00447BBC
0044B81C MOV EAX,EBX
0044B81E CALL Project1.0042DF74
0044B823 POP EBX
0044B824 RETN
We set a breakpoint on SetWindowPos and you will fiind:
0044FDC8 PUSH EBP
0044FDC9 MOV EBP,ESP
0044FDCB PUSH EBX
0044FDCC MOV EBX,EAX
0044FDCE MOV EAX,DWORD PTR SS:[EBP+8]
0044FDD1 MOV EAX,DWORD PTR DS:[EAX-4] ; mov in eax contents of DWORD
PTR DS:[453B40], now EAX = 00951294
0044FDD4 MOV EAX,DWORD PTR DS:[EAX+30h] ; hwnd pointed by DS:[009512C4]
hWnd = 'Project1',class='TApplication'
0044FDD7 PUSH EAX ; hWnd
0044FDD8 CALL JMP.&user32.IsWindowVisible
0044FDDD CMP EAX,1
0044FDE0 SBB EAX,EAX
0044FDE2 INC EAX
0044FDE3 CMP AL,BYTE PTR DS:[451FCC]
0044FDE9 JNZ SHORT .0044FE1E
0044FDEB CMP BL,BYTE PTR DS:[451FCC]
0044FDF1 JE SHORT .0044FE1E
0044FDF3 MOVZX EAX,BL

0044FDF6 MOVZX EAX,WORD PTR DS:[EAX*2+451FD0] ; we patch this to put in


eax 97h so the form will be hidden!
0044FDFE PUSH EAX
; Flags = SWP_NOSIZE|SWP_NOMOVE|
SWP_NOZORDER|SWP_NOACTIVATE|SWP_HIDEWINDOW (97h)
0044FDFF PUSH 0
; Height = 0
0044FE01 PUSH 0
; Width = 0
0044FE03 PUSH 0
;Y=0
0044FE05 PUSH 0
;X=0
0044FE07 PUSH 0
; InsertAfter = HWND_TOP
0044FE09 MOV EAX,DWORD PTR SS:[EBP+8]
0044FE0C MOV EAX,DWORD PTR DS:[EAX-4]
; For Form1 - 00951294
0044FE0F MOV EAX,DWORD PTR DS:[EAX+30] ; handle of Window
0044FE12 PUSH EAX ; hWnd = 001700A2 ('Project1',class='TApplication')
0044FE13 CALL JMP.&user32.SetWindowPos
0044FE18 MOV BYTE PTR DS:[451FCC],BL
0044FE1E POP EBX
0044FE1F POP EBP
0044FE20 RETN
When the form is showed SWP_HIDEWINDOW (97h) is replaced by
SWP_SHOWWINDOW (value is 57h)
Few line down you will see:
0044FE24 PUSH EBP
0044FE25 MOV EBP,ESP
0044FE27 PUSH ECX
0044FE28 PUSH EBX
0044FE29 PUSH ESI
0044FE2A PUSH EDI
0044FE2B MOV DWORD PTR SS:[EBP-4],EAX
0044FE2E MOV EAX,DWORD PTR SS:[EBP-4]
0044FE31 CMP DWORD PTR DS:[EAX+30],0
0044FE35 JE SHORT .0044FEA3
0044FE37 MOV EAX,DWORD PTR DS:[454B44]
0044FE3C CALL .0044CA00
0044FE41 MOV ESI, EAX ; return number of Forms (03)
0044FE43 DEC ESI
0044FE44 TEST ESI,ESI
0044FE46 JL SHORT .0044FE9A
0044FE48 INC ESI
0044FE49 XOR EDI,EDI
; prepare the counter
0044FE4B MOV EDX,EDI ; begin of loop
0044FE4D MOV EAX,DWORD PTR DS:[454B44]
0044FE52 CALL .0044C9EC
0044FE57 MOV EBX,EAX
0044FE59 CMP BYTE PTR DS:[EBX+57],0 ; always 0 when is hidden while when is
showed is second time 1
0044FE5D JE SHORT .0044FE96
0044FE5F CMP DWORD PTR DS:[EBX+198],0

0044FE66
0044FE68
0044FE6A
0044FE6F
0044FE71
0044FE73
0044FE79
0044FE7A
0044FE7C
0044FE81
0044FE82
0044FE87
0044FE89
0044FE8B
0044FE8C
0044FE8E
0044FE93
0044FE94
0044FE96
0044FE97
0044FE98
0044FE9A
0044FE9B
0044FE9D
0044FEA2
0044FEA3
0044FEA4
0044FEA5
0044FEA6
0044FEA7
0044FEA8

JE SHORT .0044FE8B
MOV EAX,EBX
CALL Project1.00434E90
TEST AL,AL
JE SHORT Project1.0044FE8B
MOV EAX,DWORD PTR DS:[EBX+198]
PUSH EAX
MOV EAX,EBX
CALL Project1.00434BBC
PUSH EAX ; hParent
CALL user32.IsChild
TEST EAX,EAX
JNZ SHORT.0044FE96
PUSH EBP
MOV AL,1
CALL .0044FDC8 ; is called when a Form is showed
POP ECX
JMP SHORT .0044FEA3
INC EDI
DEC ESI
JNZ SHORT .0044FE4B
PUSH EBP
XOR EAX,EAX
CALL .0044FDC8 ; is called when a Form is hidden
POP ECX
POP EDI
POP ESI
POP EBX
POP ECX
POP EBP
RETN

This is all.
I hope you enjoy reading this.

You might also like