Finding standard functions in Delphi/C++ Builder
Knowing is better than searching
+HCU Papers
Papers
20 July 1999
by LaZaRuS
Courtesy of Fravia's page of reverse engineering
fra_00xx
980720
LaZaRuS
1000
PA
xx
"No special target. You can use any program that is written in either C++ Builder or Delphi and has the "feature" I describe...", OK, I'm heavily biased, but I must tell you that when I read something like this, my heart tells me: this guy is GOOD! And indeed here you have a "beginner" essay that IMO well deserves his place among the "papers" section: what we are trying to do is to understand fundamental parameters of software engineering (actually: re-engineering :-) that should be valid well over a specific case. Admittedly, a particularly difficult protection scheme, of a very specific target, can at times teach us a lot. Yet, unfortunately, many young and at times plainly talented crackers dump hundreds of very specific target-related essays in my mailbox, and it is always difficult to explain them why a particular essay on how to make a specific key-generator is NOT worth publishing, even if the Author clearly worked a lot. And I always feel sorry to refuse in such cases, and seek ways to explain. Maybe reading this good, target unrelated, essay all those friends will understand why: most of the time we want to apply what we learn to completely different situations. And that's the FUN of reversing: that you learn things you can really use to go on. Else you could as well just publish huge lists of serials and ready-made cracks for the zombies.
And yes, LaZaRuS, "goddam" is "reversically correct" :-)
And yes, LaZaRuS: we can have a project at fravia's like "Optimizing the Delphi compiler" where in the end we have a small program that removes the overbloated sections by NOPs and cleaner code? If somebody works on such an interesting project (you?) I'll give him all the space (and audience) desired.
There is a crack, a crack in everything That's how the light gets in
Rating
(X)Beginner ( )Intermediate ( )Advanced ( )Expert

A useful essay for guys that prefer the deadlisting approach instead of tracing through the code for hours, but have some starting problems when the coder tried to hide any starting point when you enter a wrong serial.
Finding standard functions in Delphi/C++ Builder
Knowing is better than searching
Written by LaZaRuS


Introduction
Today, most shareware applications are written in either Borland Delphi or Visual Basic. These overbloated "high-level" (in reality they are lower than low) languages always link their goddamn XXXKB huge runtime module either dynamically or statically to the exe files. These runtime modules always contain the same code (of course) with the same overbloated procedures and functions. This means the function that displays a messagebox or closes a window should be generally the same in Delphi 1.0 - Delphi 4.0 and C++ Builder 1.0 - 4.0 should be quite the same, too. So why not finding these functions and using them for our business when standard approaches to crack a program fail (Now I am talking about myself. I consider myself a "learning reverser" and sadly I still fail often - I don't know about you, dear reader :-)
The point is: For example we have a program that does nothing but closing the "register" window when we enter a wrong serial. No clues in the string references, no breakpoint works, nothing! We could easily find the important code if we set a breakpoint inside the "Close Window" call of the Delphi runtime module and step through it until a "ret" follows and leads us to the code section that calculates the serial. This essay will cover the functions that close a modal form, display one, enable a button, display a messagebox and set text to an edit field.

Tools required
If you want to try what I tell you, you should have either a version of Borland Delphi and/or Borland C++ Builder and a version of W32Dasm.

Target's URL/FTP
No special target. You can use any program that is written in either C++ Builder or Delphi and has the "feature" I describe.

Essay

Preface



It's quite easy to find the correct code in a deadlisting. For that purpose I just wrote

a small program that did nothing, but this, when the "register" button was pushed:

(From now on I will use C++ Builder syntax; Delphi syntax is quite the same: For my code

examples, just replace all "->" with ".")



MessageBeep(0);

HereComesTheCodeIWantToExamine();

MessageBeep(0);



HereComesTheCodeIWantToExamine();

stands for either

1.Form2->Close();

2.Form3->ShowModal();

3.Button2->Enabled=true;

4.Application->MessageBox("Text","Caption",MB_OK);

5.Edit1->Text="Wrong";



To describe my program: It has two forms - On Form1 there is a button (OnClick Form2 is 

displayed) - Form2->Contains one button and one edit field - The button sets text to the

edit field. I have chosen to take the MessageBeep() function to locate the important 

code in the deadlisting as this is the "cleanest" function I know. Just one push and 

then a call to USER32.MESSAGEBEEP. Everything between the two Beeps is of importance.



(From now on, when I say "handle" of something I mean the first part in the memory that

describes the component)



Let's start with closing a form:

In C++ Builder this is achieved with Form2->Close();

so my code looks like this:



void __fastcall TForm2::Button1Click(TObject *Sender)

{

  MessageBeep(0);

  Form2->Close(); 

  MessageBeep(0);

}





I compiled the program and looked at it in W32Dasm.



:00401860 6A00                    push 00000000 ;; push sound 0



* Reference To: USER32.MessageBeep, Ord:0000h

                                  |

:00401862 E85DDA0200              Call 0042F2C4 ;; Beep

:00401867 A1A4494300              mov eax, dword ptr [004349A4]

:0040186C E84F330100              call 00414BC0

:00401871 6A00                    push 00000000 ;; push sound 0



* Reference To: USER32.MessageBeep, Ord:0000h

                                  |

:00401873 E84CDA0200              Call 0042F2C4;; Beep



Only two lines that are important. In line :00401867 the handle of the window that should be

closed is pushed, in :0040186C the function that closes the window is called. Let's enter 

the call to see which nice ASM code we will meet there:



* Referenced by a CALL at Addresses:

|:0040186C   , :00414470   , :00415F2F

|

:00414D1C 53                      push ebx

:00414D1D 51                      push ecx

:00414D1E 8BD8                    mov ebx, eax ;; ebx = handle of Form

:00414D20 F6833201000008          test byte ptr [ebx+00000132], 08

:00414D27 740D                    je 00414D36

:00414D29 C7834401000002000000    mov dword ptr [ebx+00000144], 00000002 ;; Close Form

:00414D33 5A                      pop edx

:00414D34 5B                      pop ebx

:00414D35 C3                      ret



It seems pretty obvious what happens here: In line :00414D1E the start of the definition of

the form that should be closed is moved to ebx. Then something is tested (I wasn't able to

figure out what), but I never experienced the jump was taken. The window is closed in line

:00414D29. Do I see a strange view in your face? Closing a window by setting just one value?



A little intermezzo:

As you might know C++ Builder and Delphi have a special way of defining windows. And - as

experienced coders in this languages should know - the Form->Close() call is not the best

way to close a modal form. The best way is setting the Form->ModalResult property to a 

value that is not zero. Then the window will disappear. So, the Form->Close() call just 

sets the ModalResult value of the Form (which is saved 144h bytes after the start of the

Form's definition) to 2 which is ID_CANCEL. Then the window disappears.



So we are inside the main function that closes a form and we can easily see from where it is

called: :0040186C, :00414470, :00415F2F - One of those calls must be the one that closes our

form (in this case the first one as we already know). The easiest way to find the correct 

call in a "Register" routine we have no clue where it is located is setting a breakpoint at

one of the lines at the "Close-the-window" function and then when the RET instruction is 

taken we know where the function is called, can easily find the "Beggar off" jump and should

have a good starting point for a crack :)



There is still one difficulty: If the coder didn't use Form->Close(), but sets the ModalResult

property directly. What will the code look like??? A small change in the program code will

reveal this (and show that it is no difficulty :) I just changed the line Form2->Close; to

Form2->ModalResult=1;



:004018D5 A1445A4300              mov eax, dword ptr [00435A44]

:004018DA C7804401000001000000    mov dword ptr [ebx+00000144], 00000001



Pretty obvious, the handle is loaded in eax and then the modal result (handle+144) is set 

to one. But wait, why is the handle loaded in eax, but the modal result is stored in 

EBX+144 ??? Just a small bug in the W32Dasm disassembling routine. When you debug the

program with W32Dasm you will see that the line mov dword ptr [ebx+00000144], 00000001 is

disassembled wrong, but executed correctly (as mov dword ptr [eax+00000144], 00000001). 



Finally we can say that it is easy to locate passages where forms are closed as there is either

the "characterizing" call passed, or the modal result at [register+00000144] is set to something

not 0. These values only fit for C++ Builder, for Delphi the values are

...

test byte ptr [ebx+0000013D], 08

...

mov dword ptr [ebx+00000150], 00000002

...







The next function we have a closer look at is Form->ShowModal() - This one is used when you

enter a wrong serial and then a dialog window appears telling you "Sorry guy".

I just changed the OnClick event of my first button to: 



void __fastcall TForm1::Button1Click(TObject *Sender)

{

  MessageBeep(0);

  Form2->ShowModal(); 

  MessageBeep(0);

}



Compiling - disassembling - searching for MessageBeep. You should see this:



:00401434 6A00                    push 00000000



* Reference To: USER32.MessageBeep, Ord:0000h

                                  |

:00401436 E895F00200              Call 004304D0

:0040143B A12C5C4300              mov eax, dword ptr [00435C2C]

:00401440 E88B3B0100              call 00414FD0

:00401445 6A00                    push 00000000



* Reference To: USER32.MessageBeep, Ord:0000h

                                  |

:00401447 E884F00200              Call 004304D0



You can easily separate the important from the unimportant section. Only two lines are 

important, :0040143B and :00401440. The first one moves the handle of the form to eax, the

second one calls a function that displays the window. You will be surprised how long this

function is, compared to the first example of the Close() function.

Here it is (absolutely uncommented as there is not even a need to have a closer look):



* Referenced by a CALL at Address:

|:00401440   

|

:00414FD0 55                      push ebp

:00414FD1 8BEC                    mov ebp, esp

:00414FD3 83C4E4                  add esp, FFFFFFE4

:00414FD6 53                      push ebx

:00414FD7 8945FC                  mov dword ptr [ebp-04], eax

:00414FDA BBD05C4300              mov ebx, 00435CD0

:00414FDF E82849FFFF              call 0040990C

:00414FE4 8B45FC                  mov eax, dword ptr [ebp-04]

:00414FE7 80783F00                cmp byte ptr [eax+3F], 00

:00414FEB 7521                    jne 0041500E

:00414FED 8B45FC                  mov eax, dword ptr [ebp-04]

:00414FF0 80784000                cmp byte ptr [eax+40], 00

:00414FF4 7418                    je 0041500E

:00414FF6 8B45FC                  mov eax, dword ptr [ebp-04]

:00414FF9 F6803201000008          test byte ptr [eax+00000132], 08

:00415000 750C                    jne 0041500E

:00415002 8B45FC                  mov eax, dword ptr [ebp-04]

:00415005 80B82F01000001          cmp byte ptr [eax+0000012F], 01

:0041500C 7516                    jne 00415024



* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:

|:00414FEB(C), :00414FF4(C), :00415000(C)

|



* Possible Reference to String Resource ID=61490: "Cannot make a visible window modal"

                                  |

:0041500E B932F00000              mov ecx, 0000F032

:00415013 B201                    mov dl, 01

:00415015 B864814000              mov eax, 00408164

:0041501A E815B60000              call 00420634

:0041501F E8E0EE0000              call 00423F04



* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0041500C(C)

|



* Reference To: USER32.GetCapture, Ord:0000h

                                  |

:00415024 E875B30100              Call 0043039E

:00415029 85C0                    test eax, eax

:0041502B 7411                    je 0041503E

:0041502D 6A00                    push 00000000

:0041502F 6A00                    push 00000000

:00415031 6A1F                    push 0000001F



* Reference To: USER32.GetCapture, Ord:0000h

                                  |

:00415033 E866B30100              Call 0043039E

:00415038 50                      push eax



* Reference To: USER32.SendMessageA, Ord:0000h

                                  |

:00415039 E8ECB40100              Call 0043052A



* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0041502B(C)

|



* Reference To: USER32.ReleaseCapture, Ord:0000h

                                  |

:0041503E E8C3B40100              Call 00430506

:00415043 8B45FC                  mov eax, dword ptr [ebp-04]

:00415046 80883201000008          or byte ptr [eax+00000132], 08



* Reference To: USER32.GetActiveWindow, Ord:0000h

                                  |

:0041504D E846B30100              Call 00430398

:00415052 8945E4                  mov dword ptr [ebp-1C], eax

:00415055 A13C244300              mov eax, dword ptr [0043243C]

:0041505A 8945F0                  mov dword ptr [ebp-10], eax

:0041505D A1D45C4300              mov eax, dword ptr [00435CD4]

:00415062 8B405C                  mov eax, dword ptr [eax+5C]

:00415065 8945EC                  mov dword ptr [ebp-14], eax

:00415068 A1D45C4300              mov eax, dword ptr [00435CD4]

:0041506D 8B4030                  mov eax, dword ptr [eax+30]

:00415070 8B55EC                  mov edx, dword ptr [ebp-14]

:00415073 E890DEFEFF              call 00402F08

:00415078 A1D45C4300              mov eax, dword ptr [00435CD4]

:0041507D 8B55FC                  mov edx, dword ptr [ebp-04]

:00415080 89505C                  mov dword ptr [eax+5C], edx

:00415083 A1D45C4300              mov eax, dword ptr [00435CD4]

:00415088 668B4038                mov ax, word ptr [eax+38]

:0041508C 668945EA                mov word ptr [ebp-16], ax

:00415090 33D2                    xor edx, edx

:00415092 A1D45C4300              mov eax, dword ptr [00435CD4]

:00415097 E8CC060000              call 00415768

:0041509C 33C0                    xor eax, eax

:0041509E E8C1BFFFFF              call 00411064

:004150A3 8945F4                  mov dword ptr [ebp-0C], eax

:004150A6 33D2                    xor edx, edx

:004150A8 55                      push ebp

:004150A9 68E9514100              push 004151E9

:004150AE 64FF32                  push dword ptr fs:[edx]

:004150B1 648922                  mov dword ptr fs:[edx], esp

:004150B4 8B45FC                  mov eax, dword ptr [ebp-04]

:004150B7 E8C8FEFFFF              call 00414F84

:004150BC 33D2                    xor edx, edx

:004150BE 55                      push ebp

:004150BF 6873514100              push 00415173

:004150C4 64FF32                  push dword ptr fs:[edx]

:004150C7 648922                  mov dword ptr fs:[edx], esp

:004150CA 6A00                    push 00000000

:004150CC 6A00                    push 00000000

:004150CE 6800B00000              push 0000B000

:004150D3 8B45FC                  mov eax, dword ptr [ebp-04]

:004150D6 E8E58AFFFF              call 0040DBC0

:004150DB 50                      push eax



* Reference To: USER32.SendMessageA, Ord:0000h

                                  |

:004150DC E849B40100              Call 0043052A

:004150E1 8B45FC                  mov eax, dword ptr [ebp-04]

:004150E4 33D2                    xor edx, edx

:004150E6 899044010000            mov dword ptr [eax+00000144], edx



* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00415129(C)

|

:004150EC 8B03                    mov eax, dword ptr [ebx]

:004150EE E825170000              call 00416818

:004150F3 8B03                    mov eax, dword ptr [ebx]

:004150F5 80787C00                cmp byte ptr [eax+7C], 00

:004150F9 740F                    je 0041510A

:004150FB 8B45FC                  mov eax, dword ptr [ebp-04]

:004150FE C7804401000002000000    mov dword ptr [ebx+00000144], 00000002

:00415108 EB14                    jmp 0041511E



* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:004150F9(C)

|

:0041510A 8B45FC                  mov eax, dword ptr [ebp-04]

:0041510D 83B84401000000          cmp dword ptr [eax+00000144], 00000000

:00415114 7408                    je 0041511E

:00415116 8B45FC                  mov eax, dword ptr [ebp-04]

:00415119 E8B6FDFFFF              call 00414ED4



* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:

|:00415108(U), :00415114(C)

|

:0041511E 8B45FC                  mov eax, dword ptr [ebp-04]

:00415121 8B8044010000            mov eax, dword ptr [eax+00000144]

:00415127 85C0                    test eax, eax

:00415129 74C1                    je 004150EC

:0041512B 8945F8                  mov dword ptr [ebp-08], eax

:0041512E 6A00                    push 00000000

:00415130 6A00                    push 00000000

:00415132 6801B00000              push 0000B001

:00415137 8B45FC                  mov eax, dword ptr [ebp-04]

:0041513A E8818AFFFF              call 0040DBC0

:0041513F 50                      push eax



* Reference To: USER32.SendMessageA, Ord:0000h

                                  |

:00415140 E8E5B30100              Call 0043052A

:00415145 8B45FC                  mov eax, dword ptr [ebp-04]

:00415148 E8738AFFFF              call 0040DBC0

:0041514D 8BD8                    mov ebx, eax



* Reference To: USER32.GetActiveWindow, Ord:0000h

                                  |

:0041514F E844B20100              Call 00430398

:00415154 3BD8                    cmp ebx, eax

:00415156 7405                    je 0041515D

:00415158 33C0                    xor eax, eax

:0041515A 8945E4                  mov dword ptr [ebp-1C], eax



* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00415156(C)

|

:0041515D 33C0                    xor eax, eax

:0041515F 5A                      pop edx

:00415160 59                      pop ecx

:00415161 59                      pop ecx

:00415162 648910                  mov dword ptr fs:[eax], edx

:00415165 687A514100              push 0041517A



* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00415178(U)

|

:0041516A 8B45FC                  mov eax, dword ptr [ebp-04]

:0041516D E80AFEFFFF              call 00414F7C

:00415172 C3                      ret





It would take quite some while to get to know what this one (and every subcall) does, but

luckily there's a little backdoor that leads us perfectly easy to the important sections.

In the first part of this essay we learned that the ModalResult propery is stored 144

bytes after the handle of the form. So let's search for "144]" and we find these lines:



:004150E6 899044010000            mov dword ptr [eax+00000144], edx

:004150FE C7804401000002000000    mov dword ptr [ebx+00000144], 00000002

:0041510D 83B84401000000          cmp dword ptr [eax+00000144], 00000000

:0041510D 83B84401000000          cmp dword ptr [eax+00000144], 00000000

:0041510D 83B84401000000          cmp dword ptr [eax+00000144], 00000000



The last three are not important as they don't set the property. They just check (for several

purposes), if the window is already modal or not. The first line displays the window (as it

sets the ModalResult property to 0). How do I know that edx is 0? Did you look at the line

right in front of it? xor edx, edx - now everything should be clear. The second line sets

the propery to 2 (ID_CANCEL) if anything happens that doesn't allow the window to be shown.

I won't have a closer look at all this here, because the topic of this essay is finding these

routines in order to set breakpoints on them, not analyzing them.









Now let's head for the function that enables a button. For this purpose I changed my prog in

this way: A edit field and a disabled button - When the text of the edit field is "H", then

the button gets enabled. Compiling and disassembling. Searching for the MessageBeeps will

reveal this (I believe that's the most overbloated code I have *ever* seen in a deadlisting):



:00401898 6A00                    push 00000000 ;; "our" first sound



* Reference To: USER32.MessageBeep, Ord:0000h

                                  |

:0040189A E8F9EC0200              Call 00430598 ;; is called here

:0040189F 66C745E40800            mov [ebp-1C], 0008 ;; --------------- All this zillions

:004018A5 8D45FC                  lea eax, dword ptr [ebp-04]         | of lines do nothing

:004018A8 E893000000              call 00401940                       | but getting the text

:004018AD 8BD0                    mov edx, eax                        | from the edit field

:004018AF FF45F0                  inc [ebp-10]                        | and compare it with

:004018B2 8B4DD0                  mov ecx, dword ptr [ebp-30]         | "H"

:004018B5 8B81CC010000            mov eax, dword ptr [ecx+000001CC]   |

:004018BB E8DC8A0000              call 0040A39C                       |

:004018C0 8D55FC                  lea edx, dword ptr [ebp-04]         |

:004018C3 52                      push edx                            |

                                                                      |

* Possible StringData Ref from Data Obj ->"H"                         |

                                  |                                   |

:004018C4 BA78164300              mov edx, 00431678                   |

:004018C9 8D45F8                  lea eax, dword ptr [ebp-08]         |

:004018CC E8D7D40000              call 0040EDA8                       |

:004018D1 FF45F0                  inc [ebp-10]                        |

:004018D4 8D55F8                  lea edx, dword ptr [ebp-08]         |

:004018D7 58                      pop eax                             |

:004018D8 E80BD80000              call 0040F0E8                       |

:004018DD 50                      push eax                            |

:004018DE FF4DF0                  dec [ebp-10]                        |

:004018E1 8D45F8                  lea eax, dword ptr [ebp-08]         |

:004018E4 BA02000000              mov edx, 00000002                   |

:004018E9 E81AD70000              call 0040F008                       |

:004018EE FF4DF0                  dec [ebp-10]                        |

:004018F1 8D45FC                  lea eax, dword ptr [ebp-04]         |

:004018F4 BA02000000              mov edx, 00000002                   |

:004018F9 E80AD70000              call 0040F008                       |

:004018FE 59                      pop ecx                             |

:004018FF 84C9                    test cl, cl;;-----------------------|

:00401901 7410                    je 00401913 ;; "beggar off" jump

:00401903 B201                    mov dl, 01 ;; "Enable button" flag

:00401905 8B45D0                  mov eax, dword ptr [ebp-30]

:00401908 8B80C8010000            mov eax, dword ptr [eax+000001C8] ;; eax gets handle of button

:0040190E E8218A0000              call 0040A334 ;; enable the button



* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00401901(C)

|

:00401913 6A00                    push 00000000 ;; and our second Beep



* Reference To: USER32.MessageBeep, Ord:0000h

                                  |

:00401915 E87EEC0200              Call 00430598 ;; is heard here



How I know, that "mov dl, 01" is a flag? I just made a program that disables the button instead

of enabling. Then the line is "xor edx, edx". A short glance into the following call would

have revealed the same.



* Referenced by a CALL at Address:

|:0040190E   

|

:0040A334 3A5040                  cmp dl, byte ptr [eax+40] ;; cmp "new" state with "old" state

:0040A337 7411                    je 0040A34A ;; return from call

:0040A339 885040                  mov byte ptr [eax+40], dl ;; set new button state

:0040A33C 6A00                    push 00000000

:0040A33E 33C9                    xor ecx, ecx

:0040A340 BA0CB00000              mov edx, 0000B00C

:0040A345 E86A070000              call 0040AAB4



* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040A337(C)

|

:0040A34A C3                      ret

:0040A34B 90                      nop





As you see, in the first line there's a check if the state the button should be set to is the

same as the old state. This one's from Borland/Inprise so I say it's optimization. If it were

from M$ I would say they want to hide that the exe crashes, if the new button state is the

same as the old one ;)

I never tried out what the call some lines later is for, as my goal is reached inside this

function.



Tracing back from this call is not as easy in a shareware program as this call is *not* taken

when you enter a wrong serial. You have to trace back manually and eliminate (by *zen*) as

many call references as possible. Then set a bp on the remaining references and find what you

search for.







Now let's head for the messagebox. Don't think it is just four pushes and one call to

USER32.MESSAGEBOX - That would be too easy. Sadly this compiler can just terribly overbloat

*everything*.



You know what to do now:

My code looked like this:



MessageBeep(0);

Application->MessageBox("","",MB_OK);

MessageBeep(0);



No Text, No Caption and only a OK button. Actually I prepared to see just one call to the

USER32.MESSAGEBOX function but what I saw there, sadly took my breath :( And slowly I began

to understand why the runtime module is >200KB



:00401434 6A00                    push 00000000



* Reference To: USER32.MessageBeep, Ord:0000h

                                  |

:00401436 E80BED0200              Call 00430146

:0040143B 6A00                    push 00000000

:0040143D B9B1134300              mov ecx, 004313B1

:00401442 BAB0134300              mov edx, 004313B0

:00401447 A1D45C4300              mov eax, dword ptr [00435CD4]

:0040144C E80FFC0100              call 00421060

:00401451 6A00                    push 00000000



* Reference To: USER32.MessageBeep, Ord:0000h



I believe there's no need to comment any more - The four values you see in front of the call

are the properties for the messagebox, the rest is well-known. The call leads to a single jump

which leads to this piece of shit (sorry: code ;)



* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00421060(U)

|

:00416774 55                      push ebp

:00416775 8BEC                    mov ebp, esp

:00416777 83C4F4                  add esp, FFFFFFF4

:0041677A 53                      push ebx

:0041677B 56                      push esi

:0041677C 57                      push edi

:0041677D 8BF9                    mov edi, ecx

:0041677F 8BF2                    mov esi, edx

:00416781 8BD8                    mov ebx, eax



* Reference To: USER32.GetActiveWindow, Ord:0000h

                                  |

:00416783 E88C980100              Call 00430014

:00416788 8945F8                  mov dword ptr [ebp-08], eax

:0041678B 33C0                    xor eax, eax

:0041678D E8C6A8FFFF              call 00411058

:00416792 8945F4                  mov dword ptr [ebp-0C], eax

:00416795 33C0                    xor eax, eax

:00416797 55                      push ebp

:00416798 68D5674100              push 004167D5

:0041679D 64FF30                  push dword ptr fs:[eax]

:004167A0 648920                  mov dword ptr fs:[eax], esp

:004167A3 0FB74508                movzx eax, word ptr [ebp+08]

:004167A7 50                      push eax

:004167A8 57                      push edi

:004167A9 56                      push esi

:004167AA 8B4320                  mov eax, dword ptr [ebx+20]

:004167AD 50                      push eax



* Reference To: USER32.MessageBoxA, Ord:0000h

                                  |

:004167AE E899990100              Call 0043014C

:004167B3 8945FC                  mov dword ptr [ebp-04], eax

:004167B6 33C0                    xor eax, eax

:004167B8 5A                      pop edx

:004167B9 59                      pop ecx

:004167BA 59                      pop ecx

:004167BB 648910                  mov dword ptr fs:[eax], edx

:004167BE 68DC674100              push 004167DC



* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:004167DA(U)

|

:004167C3 8B45F4                  mov eax, dword ptr [ebp-0C]

:004167C6 E841A9FFFF              call 0041110C

:004167CB 8B45F8                  mov eax, dword ptr [ebp-08]

:004167CE 50                      push eax



* Reference To: USER32.SetActiveWindow, Ord:0000h

                                  |

:004167CF E8D2990100              Call 004301A6

:004167D4 C3                      ret



What the hell is the compiler doing here??? Wouldn't it be easier to call the MessageBox

function directly, like in Win32Asm??? BTW: This approach was not as valuable as the others

as a breakpoint at MessageBox *will* work here. In the other examples there were no API calls

we could break on.

Slow but sure, I loose my deep respect to Borland's coders :( or do I have too few

knowledge about compilers ?







Let's head to our last (and one more valuable one as the last one). What happens if the text

is written to an edit field?



My code looked like this (OnClick event of a Button)



MessageBeep(0);

Edit1->Text="H";

MessageBeep(0);



In W32Dasm I found this:



:0040187E 6A00                    push 00000000



* Reference To: USER32.MessageBeep, Ord:0000h

                                  |

:00401880 E88BEC0200              Call 00430510 ;; our Beep

:00401885 66C745E80800            mov [ebp-18], 0008



* Possible StringData Ref from Data Obj ->"H"

                                  |

:0040188B BA48164300              mov edx, 00431648 ;; our "H"

:00401890 8D45FC                  lea eax, dword ptr [ebp-04]

:00401893 E888D40000              call 0040ED20

:00401898 FF45F4                  inc [ebp-0C]

:0040189B 8B10                    mov edx, dword ptr [eax] ;; our "H" again

:0040189D 8B4DD4                  mov ecx, dword ptr [ebp-2C]

:004018A0 8B81CC010000            mov eax, dword ptr [ecx+000001CC] ;; This is the text property

:004018A6 E8998A0000              call 0040A344

:004018AB FF4DF4                  dec [ebp-0C]

:004018AE 8D45FC                  lea eax, dword ptr [ebp-04]

:004018B1 BA02000000              mov edx, 00000002

:004018B6 E8C5D60000              call 0040EF80

:004018BB 6A00                    push 00000000 ;; and our beep again



* Reference To: USER32.MessageBeep, Ord:0000h

                 |

:004018BD E84EEC0200              call 00430510 ;; BEEP





This time it is pretty much again. (Wouldn't a simple call to SetWindowTextA be enough?)

I tried to understand what's going on in the calls that are listened here, but there are

more than 5 levels of subcalls following and I decided to leave this to someone with more

knowledge about the Delphi/C++ Builder compiler as we reached our goal: We know that the

text property is saved 1CCh (see line :004018A0) bytes after the handle of the edit field.





Now a short comprehension: Finding the functions that close and show windows can be done

by looking for "+00000144]" in W32Dasm. +00000040] will lead us to the function that 

enables a button. To locate the MessageBox function search for "MessageBox" and look if 

there's a GetActiveWindow in front of it and a SetActiveWindow following. The function that

writes text to an edit field can be found by looking for +000001CC]. (This values are for 

C++ Builder)



Sadly, I cannot present you the Delphi values as I do not have a current version of Delphi

(only 2.0). And the values from this version differ to the values of later versions. But

nevertheless the way to find them is the same and you can even find them in a RTM of a

program you don't even kwow. In this way I found the values I presented you above for

closing modal forms.

Whatever, I try to get a newer version of Delphi as soon as possible and will add the values

then.

Final Notes

In the last days I saw so many things inside the Delphi compiler I didn't like. For example

the goddamn overbloated MessageBox funtion Delphi uses. Shouldn't is be possible to NOP most

of it out and just make one call to USER32.MESSAGEBOXA? This could nicely increase the speed

of execution. I'll give it a shot later (I'll probably fail due my lack of ASM knowledge), 

but perhaps we can have a project at fravia's page like "Optimizing the Delphi compiler" where

in the end we have a small program that removes the overbloated sections by NOPs and cleaner 

code?

 

Comments, additions, whatever: lazarus_hf@hotmail.com





Ob Duh
I wont even bother explaining you that there's no target at all, so you'r inside a "pure reversing" essay. Just enjoy and thank people that spent a little of their time and of their (alas short!) life to give you something valuable for free.

You are deep inside fravia's page of reverse engineering, choose your way out:


redhomepage redlinks redsearch_forms red+ORC redhow to protect redacademy database
redreality cracking redhow to search redjavascript wars
redtools redanonymity academy redcocktails redantismut CGI-scripts redmail_fravia+
redIs reverse engineering legal?