An experiment of RE- engineering for Object Pascal programs.
Sample:dbexplorer 4.00 (c)Inprise Corp.1995-1998.

Published by +Tsehp March 2000

PART I -The PROBLEM
        Once upon a time, my brothers DB programmers complained to  me, that the life
 is not so beautiful as it might be.) The point is that Dbexplorer (by the way ,it is
 a tool for reversing databases logic)has some (or better to say has not) features ,
that  degrade productivity of a programmer. If you do not know,the Program dbexplor.exe
 is a standard tool for designing SQL databases in DELPHI and C++ BUILDER. The program
has several lacks of options and one of them is very annoying. Edit fields of the program
have no string and character numeration. However sql server  often gives an error message,
which points to specific location:
General SQL error.
Token unknown - line 193, char 91
fromsfhM
 
        but it is not so eazy to locate the error .The serious "STORED PROCEDURE" or
"TRIGGER" can take several pages of text.

        Before I begin to describe REVERSE ENGINEERING and REENGINEERING of the program,
let me say some words to a reader , that   did not see DELPHI and knows nothing about
principles of some Visual programming systems.
        For preventing re-storing the same code , that can turn us to  store megs of
useless information, Windows (and some other modern operating systems )uses,DYNAMIC LINK
LIBRARIES,or DLLs(Dynamic Load Library).Delphi uses it's own format of the libraries ,
called Packages.In fact they are  DLLs,no doubt.
        The packages are  of interest to as with two reasons:
                1) DBEXPLOR.exe -is just a shell for loading package  dbx40.bpl
                2) There are functions and classes  methods address (and names) exported
from packages,including type info.( C++ mangled names)

        And here is some information about calling conventions (convention about parameters
passing and stack correction). As it widely known DeLpHi use  "fastcall"  or "Register"
convention ,i.e. first 3 arguments passed through eax,edx,ecx respectively and others are
 pushed to Stack left to right.

Example:

a:= The_FuncTioN(first,second,sird,fourth,fifth)  ;

//compiled to  

	mov  eax,[first]
	mov edx,[second]
	mov ecx,[sird]
	push [fourth]
	push [fifth]
	call The_FuncTioN
	mov [a],eax

	

To understand the following listings you need to note that in class methods, there is
 a hidden first parameter Self (this in C++)-  pointer to object instance,which owned the method.
So parameter numeration is  right shifted by. As i can see it was implemented for making  possible
 de -referencing of object's instance's fields(data members).By the way in Delphi  this->firstdword
is address of class VMT(virtual methods table).
        Well, we are ready for rock and roll. What do we need  to begin coding? we need to decide,
what we gonna do. Making the task done with traditional  WINDOWS  programming ,we 'd need to get
HWND of multiedit control , and make subclassing of the window OR intercept it's WndProc and
re-code it to make it  do what we need .Following the ways drives us to  a long process of  code
analyzis and deep Thinking,and after that we can only constatate that the second way is impossible,
as the WndProc of the TMemo(BORLAND's encapsulated multiline edit)resides in a VCL40.bpl -a
placeholder for many standard windows controls and other components of  VCL(VISUAL COMPONENTS
 LIBRARY- DELPHI- C++ BUILDER), so the module is common for several others applications and we
can not modify it without affecting  them.
        The way of  subclassing  pushes us to reverse object mechanics  to find TMemo.Handle-
hwnd of the object.
        But there is another way :-to write additional code , wich repeats the code  generated
by compiler ,weather we decided to write it , having the source of the program.
        Let us make a model of the program,where Tmemo object'd tell us about cursor position
in it.
PART II -the point of no returning

        Let us create a new Delphi Progect .I have used Delphi  4.0 , because of gesture, that
SQL explorer 4.00  was compiled with the  version of compiler . Drop to the form a Tmemo,
Tbutton and a TStatusBar components. Let us code event handlers  ONCLICK,ONKEYUP è ONKEYDOWN
to make them find cursor position and write it to StatusBar:



unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    StatusBar1: TStatusBar;
    procedure Button1Click(Sender: TObject);
    procedure coordpicker2(Sender: TObject);


  private
  procedure coordpicker(Sender: TObject; var Key: Word; Shift: TShiftState) ;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
procedure Tform1.coordpicker(Sender: TObject; var Key: Word; Shift: TShiftState) ;

begin
coordpicker2(sender);

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
memo1.OnClick  :=coordpicker2;
memo1.onkeydown:=coordpicker;
memo1.onkeyup  :=coordpicker;
 adding handlers
end;



procedure TForm1.coordpicker2(Sender: TObject);

var startt,endt:integer;//variables
begin
tcontrol(sender).perform(EM_GETSEL,dword(@startt),dword(@endt));
//number of symbol under the cursor->startt

endt:=tcontrol(sender ).perform(EM_LINEFROMCHAR,startt,0);
//number of line ->endt

startt :=startt- tcontrol(sender).perform(EM_LINEINDEX,endt,0);
//number of symbol from the begining of the line->startt

inc(startt);
inc (endt);
//WINDOWS returns  0 based values


statusbar1.SimpleText:=format('[%8d:%8d]',[endt,Start]);
// output to statusbar


end;

end.
	

Compile the project , setting "compile with packages "  to "ON".
Load the file to  Interactive DisAssembler (IDA 3.84), demo version does fit the goal
as the file is less than 64kb.
and we have the code:
(with some comments)



;CODE:00401810 
; ??????????????? S U B	R O U T I N E ???????????????????????????????????????

; Attributes: library function bp-based	frame
 
;procedure Tform1.coordpicker(Sender: TObject; var Key: Word; Shift: TShiftState) ;
;begin
;coordpicker2(sender);
;end;


coordpicker	proc near		; DATA XREF: _TForm1_Button1Click+1Co
					; _TForm1_Button1Click+2Co
		push	ebp
		mov	ebp, esp
		call	_TForm1_coordpicker2
		pop	ebp
		retn	4
coordpicker	endp


; ??????????????? S U B	R O U T I N E ???????????????????????????????????????

;procedure TForm1.Button1Click(Sender: TObject);
;begin
;memo1.OnClick  :=coordpicker2;
;memo1.onkeydown:=coordpicker;
;memo1.onkeyup  :=coordpicker;
;end;

_TForm1_Button1Click proc near		; DATA XREF: CODE:004017B5o
		mov	edx, [eax+2C4h]
		mov	[edx+108h], eax
		mov	dword ptr [edx+104h], offset _TForm1_coordpicker2
		mov	[edx+1B4h], eax
		mov	dword ptr [edx+1B0h], offset coordpicker
		mov	[edx+1C4h], eax
		mov	dword ptr [edx+1C0h], offset coordpicker
		retn	
_TForm1_Button1Click endp

; ???????????????????????????????????????????????????????????????????????????
		align 4

; ??????????????? S U B	R O U T I N E ???????????????????????????????????????

; Attributes: bp-based frame

_TForm1_coordpicker2 proc near		; CODE XREF: coordpicker+3p
					; DATA XREF: CODE:004017C8o ...
procedure TForm1.coordpicker2(Sender: TObject);
var_1C   = dword	ptr -1Ch
var_18   = byte ptr -18h
var_14   = dword	ptr -14h
var_10   = byte ptr -10h
var_C    = dword	ptr -0Ch
var_8    = dword	ptr -8;var endt:integer;vars
var_4    = dword	ptr -4;var startt:integer;//vars


		push	ebp
		mov	ebp, esp
		add	esp, 0FFFFFFE4h
		push	ebx
		push	esi
		push	edi
		xor	ecx, ecx
		mov	[ebp+var_C], ecx
		mov	ebx, edx
		mov	edi, eax
		xor	eax, eax
		push	ebp
		push	offset loc_0_401906
		push	dword ptr fs:[eax]
		mov	fs:[eax], esp
;exception handler
		lea	eax, [ebp+var_8]
		push	eax
		lea	ecx, [ebp+var_4]
		mov	edx, 0B0h
		mov	esi, ebx
		mov	eax, esi
		call	Controls::TControl::Perform(uint,int,int)
;tcontrol(sender).perform(EM_GETSEL,dword(@startt),dword(@endt));
		push	0
		mov	ecx, [ebp+var_4]
		mov	edx, 0C9h
		mov	eax, esi
		call	Controls::TControl::Perform(uint,int,int)
		mov	[ebp+var_8], eax
;endt:=tcontrol(sender ).perform(EM_LINEFROMCHAR,startt,0);
		push	0
		mov	ecx, [ebp+var_8]
		mov	edx, 0BBh
		mov	eax, esi
		call	Controls::TControl::Perform(uint,int,int)
		sub	[ebp+var_4], eax
;startt :=startt- tcontrol(sender).perform(EM_LINEINDEX,endt,0);
		inc	[ebp+var_4]
;inc(startt);;
		inc	[ebp+var_8]
;inc (endt);
		lea	eax, [ebp+var_C]
		push	eax
		mov	eax, [ebp+var_8]
		mov	[ebp+var_1C], eax
		mov	[ebp+var_18], 0
		mov	eax, [ebp+var_4]
		mov	[ebp+var_14], eax
		mov	[ebp+var_10], 0
		lea	edx, [ebp+var_1C]
		mov	ecx, 1
		mov	eax, offset _str___8d__8d_.Text
		call	Sysutils::Format(System::AnsiString,System::TVarRec *,int)
		mov	edx, [ebp+var_C]
		mov	eax, [edi+2CCh]
		call	Comctrls::TStatusBar::SetSimpleText(System::AnsiString)
;statusbar1.SimpleText:=format('[%8d:%8d]',[endt,Start]);
		xor	eax, eax
		pop	edx
		pop	ecx
		pop	ecx
		mov	fs:[eax], edx
		push	offset loc_0_40190D

loc_0_4018FD:				; CODE XREF: _TForm1_coordpicker2+B7j
;finally  

		lea	eax, [ebp+var_C]
		call	System::`intcls'::LStrClr(System::AnsiString &)
;destroy the temporary string  
		retn	
; ???????????????????????????????????????????????????????????????????????????

loc_0_401906:				; DATA XREF: _TForm1_coordpicker2+15o
		jmp	loc_0_401018
; ???????????????????????????????????????????????????????????????????????????
		jmp	short loc_0_4018FD
;Except 
; ???????????????????????????????????????????????????????????????????????????
;
loc_0_40190D:				; DATA XREF: _TForm1_coordpicker2+A4o
		pop	edi
		pop	esi
		pop	ebx
		mov	esp, ebp
		pop	ebp
		retn	
_TForm1_coordpicker2 endp

; ???????????????????????????????????????????????????????????????????????????
_str___8d__8d_	dd 0FFFFFFFFh		; _top ; DATA XREF: _TForm1_coordpicker2+84o
		dd 9			; Len
		db '[%8d:%8d]',0        ; Text
		align 4



Explore the listing .As you can see ,the talks of overbloated code from Delphi
compiler is a bit false, we can not see anything , that  our program does not need,so
we can simply copy the code to  dbx40.bpl body(making some changes, however).Note that
before using an object's method , register EAX is filled with object address. This address
is taken from  some offset of the object , containing that one (a parent object).

                mov     eax, [edi+2CCh]
                call    Comctrls::TStatusBar::SetSimpleText(System::AnsiString)


        The offsets is uncially defined by the compiler for every  object in a program,
and we'll see how easy we can find them.
	Note a  very important detail , installing event handlers.


_TForm1_Button1Click proc near		; DATA XREF: CODE:004017B5o
		mov	edx, [eax+2C4h]; edx:=Memo1;
		mov	[edx+108h], eax; eax=form1
		mov	dword ptr [edx+104h], offset _TForm1_coordpicker2;OnClick
		mov	[edx+1B4h], eax
		mov	dword ptr [edx+1B0h], offset coordpicker ;OnKeyDown
		mov	[edx+1C4h], eax
		mov	dword ptr [edx+1C0h], offset coordpicker ;OnKeyUp
		retn	
_TForm1_Button1Click endp
      
	  The detail is - offsets to Events, and the fact , that event is actually
 two dwords-,

struct EVENT
DWORD PROCADDRES
DWORD OBJECTADDRESS
ends

OBJECTADDRESS  is an object reference(self,this), the value is transmitted to eax
before call to an object's event handler.

PART III -CULMINATION
	So this time to look at the main module of SQL EXPLORER- dbx40.bpl
First,We need to find two objects  of type  Òìåìî and TStatusBar.
we'll do it easy and elegant .Open  "Names"  and find "SetSimpleText"
let us check the first reference...

  mov     eax, [ebp+var_C]
  mov     eax, [eax+54Ch]; ;EuRiCa!
  mov     edx, [ebp+var_18]
  call    Comctrls::TStatusBar::SetSimpleText


Further , scrolling the disassembler's listing i found  this
(i am very lucky person:).




CODE:4104DA7F                 dw 500h
CODE:4104DA81                 dw 0
CODE:4104DA83                 dw 0Eh
CODE:4104DA85                 db 9,'QueryGrid'
CODE:4104DA8F                 dw 504h
CODE:4104DA91                 dw 0
CODE:4104DA93                 dw 6
CODE:4104DA95                 db 9,'QueryMemo' 
CODE:4104DA9F                 dw 508h
CODE:4104DAA1                 dw 0
CODE:4104DAA3                 dw 2
CODE:4104DAA5                 db 10,'QueryPanel'
CODE:4104DAB0                 dw 50Ch
CODE:4104DAB2                 dw 0


        One  need not to be a genius to understand what is what. offset 504h
from the beginning of main form object is the reference to  QueryMemo - must be
a field where we edit SQL queries.
some lines  after the text we can see an facts , that tell us:"You are on
the right way , boy" :



CODE:4104DBD8                 dw 54Ch
CODE:4104DBDA                 dw 0
CODE:4104DBDC                 dw 11h
CODE:4104DBDE                 db 9,'StatusBar'


and some lnes above:

CODE:4104D22F                 dw 2E4h
CODE:4104D231                 dw 0
CODE:4104D233                 dw 6
CODE:4104D235                 db 14,'DefinitionMemo'
CODE:4104D244                 dw 2E8h



        So, we have found all the components,let us find the place to
link our code to program , and of course the place for new code itself.
For soft embedding,let us extend FormCreate function, found in listing here:




 dd offset  _TDbExplorerForm_FormCreate;410510c4
 db 10,'FormCreate'



        insert there an address of empty space:41068ñ6f, and start
to copy code from another instance of IDA




CODE:41068C6F theplacefornewc:                        ; DATA XREF: CODE:4104DDAE?o
CODE:41068C6F                 nop
CODE:41068C70                 push    eax
CODE:41068C71                 push    edx
CODE:41068C72                 mov     edx, [eax+2E4h] ; sqlQuery
CODE:41068C78                 call    $+5 almost virus tech
CODE:41068C7D                 pop     ebx
CODE:41068C7E                 sub     ebx, 58C7Dh;in åâõ òåïåðü  we have BASEADDRESS
CODE:41068C84                 mov     [edx+108h], eax
CODE:41068C8A                 lea     esi, [ebx+58D00h]
CODE:41068C90                 mov     [edx+104h], esi
CODE:41068C96                 mov     [edx+1B4h], eax
CODE:41068C9C                 lea     esi, [ebx+58DF6h]
CODE:41068CA2                 mov     [edx+1B0h], esi
CODE:41068CA8                 mov     [edx+1C4h], eax
CODE:41068CAE                 lea     esi, [ebx+58DF6h]
CODE:41068CB4                 mov     [edx+1C0h], esi
CODE:41068CBA                 mov     edx, [eax+504h] ; definition
CODE:41068CC0                 mov     [edx+108h], eax
CODE:41068CC6                 lea     esi, [ebx+58D00h]
CODE:41068CCC                 mov     [edx+104h], esi
CODE:41068CD2                 mov     [edx+1B4h], eax
CODE:41068CD8                 lea     esi, [ebx+58DF6h]
CODE:41068CDE                 mov     [edx+1B0h], esi
CODE:41068CE4                 mov     [edx+1C4h], eax
CODE:41068CEA                 lea     esi, [ebx+58DF6h]
CODE:41068CF0                 mov     [edx+1C0h], esi
CODE:41068CF6                 pop     edx
CODE:41068CF7                 pop     eax
CODE:41068CF8                 add     ebx, 410C4h
CODE:41068CFE                 jmp     ebx
CODE:41068D00
CODE:41068D00 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
CODE:41068D00
CODE:41068D00 ; Attributes: bp-based frame
CODE:41068D00
CODE:41068D00 clicks          proc near               ; CODE XREF: keys?p
CODE:41068D00
CODE:41068D00 var_1C          = byte ptr -1Ch
CODE:41068D00 var_18          = byte ptr -18h
CODE:41068D00 var_14          = dword ptr -14h
CODE:41068D00 var_10          = byte ptr -10h
CODE:41068D00 dinARSTRT       = dword ptr -0Ch
CODE:41068D00 start           = dword ptr -8
CODE:41068D00 end             = dword ptr -4
CODE:41068D00
CODE:41068D00                 push    ebp
CODE:41068D01                 mov     ebp, esp
CODE:41068D03                 sub     esp, 1Ch
CODE:41068D06                 push    ebx
CODE:41068D07                 push    esi
CODE:41068D08                 push    edi
CODE:41068D09                 xor     ecx, ecx
CODE:41068D0B                 mov     [ebp+dinARSTRT], ecx
CODE:41068D11                 mov     ebx, edx
CODE:41068D13                 mov     edi, eax
CODE:41068D15                 xor     eax, eax
CODE:41068D17                 test    edi, edi;  debug remains , always true
CODE:41068D19                 jnz     short loc_0_41068D23
CODE:41068D1B                 jmp     loc_0_41068DEF;//eliminated  try-except-finally
CODE:41068D1B ; -----------------------------------------------------------------------
CODE:41068D20                 db  64h ; d
CODE:41068D21                 db  89h ; ?
CODE:41068D22                 db  20h ;
CODE:41068D23 ; -----------------------------------------------------------------------
CODE:41068D23
CODE:41068D23 loc_0_41068D23:                         ; CODE XREF: clicks+19?j
CODE:41068D23                 lea     eax, [ebp-8]
CODE:41068D29                 push    eax
CODE:41068D2A                 lea     ecx, [ebp-4]
CODE:41068D30                 mov     edx, 0B0h
CODE:41068D35                 mov     esi, ebx
CODE:41068D37                 mov     eax, esi
CODE:41068D39                 call    Controls::TControl::Perform
CODE:41068D3E                 push    0
CODE:41068D40                 mov     ecx, [ebp-4]
CODE:41068D46                 mov     edx, 0C9h
CODE:41068D4B                 mov     eax, esi
CODE:41068D4D                 call    Controls::TControl::Perform
CODE:41068D52                 mov     [ebp-8], eax
CODE:41068D58                 push    0
CODE:41068D5A                 mov     ecx, [ebp-8]
CODE:41068D60                 mov     edx, 0BBh
CODE:41068D65                 mov     eax, esi
CODE:41068D67                 call    Controls::TControl::Perform
CODE:41068D6C                 sub     [ebp+end], eax
CODE:41068D72                 inc     [ebp+end]
CODE:41068D78                 inc     [ebp+start]
CODE:41068D7E                 lea     eax, [ebp+dinARSTRT]
CODE:41068D84                 push    eax
CODE:41068D85                 mov     eax, [ebp+start]
CODE:41068D8B                 mov     dword ptr [ebp+var_1C], eax
CODE:41068D91                 mov     [ebp+var_18], 0
CODE:41068D98                 mov     edx, [ebp+end]
CODE:41068D9E                 mov     [ebp+var_14], edx
CODE:41068DA4                 mov     [ebp+var_10], 0
CODE:41068DAB                 lea     edx, [ebp+var_1C]
CODE:41068DB1                 mov     ecx, 1
CODE:41068DB6                 call    $+5
CODE:41068DBB                 pop     eax
CODE:41068DBC                 sub     eax, 58DBBh
CODE:41068DC1                 add     eax, 8E5A8h
CODE:41068DC6                 call    Sysutils::Format
CODE:41068DCB                 mov     edx, [ebp+dinARSTRT]
CODE:41068DD1                 mov     eax, [edi+54Ch]
CODE:41068DD7                 call    Comctrls::TStatusBar::SetSimpleText
CODE:41068DDC                 xor     eax, eax
CODE:41068DDE
CODE:41068DDE loc_0_41068DDE:
CODE:41068DDE                 jmp     short loc_0_41068DE4;//the remains of  try-except-finally
CODE:41068DDE ; -------------------------------------------------------------------
CODE:41068DE0                 dd 10896459h
CODE:41068DE4 ; -------------------------------------------------------------------
CODE:41068DE4
CODE:41068DE4 loc_0_41068DE4:                         ; CODE XREF: clicks+DE?j
CODE:41068DE4                 lea     eax, [ebp+dinARSTRT]
CODE:41068DEA                 call    System::`intcls'::LStrClr
CODE:41068DEF
CODE:41068DEF loc_0_41068DEF:                         ; CODE XREF: clicks+1B?j
CODE:41068DEF                 pop     edi
CODE:41068DF0                 pop     esi
CODE:41068DF1                 pop     ebx
CODE:41068DF2                 mov     esp, ebp
CODE:41068DF4                 pop     ebp
CODE:41068DF5                 retn
CODE:41068DF5 clicks          endp
CODE:41068DF5
CODE:41068DF6
CODE:41068DF6 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
CODE:41068DF6
CODE:41068DF6
CODE:41068DF6 keys            proc near
CODE:41068DF6                 call    clicks
CODE:41068DFB                 retn    4
CODE:41068DFB keys            endp
CODE:41068DFB
CODE:41068DFB ; -----------------------------------------------------------------------



EPILOG
NOTES:ida not allow you to assemble functions calls with offsets , so you must manually patch opcodes,write e8 and the offset of the function. Using packages makes your program extremely easy to reverse engineer. This is all. Look at those listings , compare them and it visible not so hard to repeat all the story with another version of DBEXPLORER.
(c) Staier from Staier.cjb.net .1999
translated- march 2000