Get Functions from DLL

delphi package - easy access to kernel objects etc.
neji
Posts: 155
Joined: Wed Mar 09, 2005 11:39 am
Contact:

Get Functions from DLL

Post by neji »

Hello madshi,

with your madKernel it's possible to get the exports from any dll.
Is it somehow possible to get also the parameters of function, the types and the calling convention?
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Nope, this information is simply not available in any normal DLL. You can use a disassembler to try to figure this out by yourself, but it's very hard.
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

If you have a program which is using the dll with export you can find out the calling convention and count of parameters. Then you can hook the function without crashing.

Every parameter is a DWORD. Everytime!
Last edited by uall on Wed Mar 22, 2006 4:15 pm, edited 1 time in total.
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

stdcall:

Code: Select all


004033B4  /$  55            PUSH EBP
004033B5  |.  8BEC          MOV EBP,ESP
004033B7  |.  5D            POP EBP
004033B8  \.  C2 1400       RETN 14



0040342C   .  6A 05         PUSH 5                                   ; /Arg5 = 00000005
0040342E   .  6A 04         PUSH 4                                   ; |Arg4 = 00000004
00403430   .  6A 03         PUSH 3                                   ; |Arg3 = 00000003
00403432   .  6A 02         PUSH 2                                   ; |Arg2 = 00000002
00403434   .  6A 01         PUSH 1                                   ; |Arg1 = 00000001
00403436   .  E8 79FFFFFF   CALL bla.004033B4                        ; \bla.004033B4
only pushed before call, ret value <> 0 -> stdcall
coutn of params = ret value div 4

for example: 0x14 div 4 = 20 div 4 = 5
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

cdecl:

Code: Select all


004033B4  /$  55            PUSH EBP
004033B5  |.  8BEC          MOV EBP,ESP
004033B7  |.  5D            POP EBP
004033B8  \.  C3            RETN


0040342C   .  6A 05         PUSH 5                                   ; /Arg5 = 00000005
0040342E   .  6A 04         PUSH 4                                   ; |Arg4 = 00000004
00403430   .  6A 03         PUSH 3                                   ; |Arg3 = 00000003
00403432   .  6A 02         PUSH 2                                   ; |Arg2 = 00000002
00403434   .  6A 01         PUSH 1                                   ; |Arg1 = 00000001
00403436   .  E8 79FFFFFF   CALL bla.004033B4                        ; \bla.004033B4
0040343B   .  83C4 14       ADD ESP,14

only pushes before call; ret value = 0 (c3) ; after call ADD ESP, xx-> cdecl

paramcount = ESP value div 4

example: ESP value = 0x14 div 4 = 20 div 4 = 5
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

register:

Code: Select all


004033B4  /$  55            PUSH EBP
004033B5  |.  8BEC          MOV EBP,ESP
004033B7  |.  5D            POP EBP
004033B8  \.  C2 0800       RETN 8


0040342C   .  6A 04         PUSH 4                                   ; /Arg2 = 00000004
0040342E   .  6A 05         PUSH 5                                   ; |Arg1 = 00000005
00403430   .  B9 03000000   MOV ECX,3                                ; |
00403435   .  BA 02000000   MOV EDX,2                                ; |
0040343A   .  B8 01000000   MOV EAX,1                                ; |
0040343F   .  E8 70FFFFFF   CALL bla.004033B4                        ; \bla.004033B4
must be register convertion: the first 3 parameters are stored in EAX, EDX, ECX all other are pushed on the stack

the count of params is:
nothing used (not MOV EAX before call) = 0
EAX used = +1; MOV EAX, .... call
EDX used = +1; MOV EDX, ... call
ECX used = +1; MOV ECX, ... call
for every PUSH = +1 or better (ret value div 4)

for the example above:

EAX is used (B8 01000000 MOV EAX,1) = 1
EDX is uded (BA 02000000 MOV EDX,2) = 1
ECX is uded (B9 03000000 MOV ECX,3) = 1
RET 8 = 8 / 4 = 2

-> 1+1+1+2 = 5 calling conversion (becasue of MOV EAX, ...) -> register
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

I hope this will help now every person who is searching for that.

if you have a function like that:

Code: Select all

GetProcAddress(dwHandle: DWord; pProcName: PChar); stdcall;
then will see something like this when its called:

Code: Select all

GPA:
....

RET 8


PUSH pProcName
PUSH dwHandle
CALL GPA

Now you know its stdcall, but you dont know the parameters.
BUT you can use this for hooking:

Code: Select all

GPACallback(a,b : DWord); stdcall;
Maybe i can write a simple program which creates the header like that. oO
If somebody is interested in it.
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

uall, have you checked out the calling convention system of win64 yet? I've tried to understand disassemblies of this system and got headaches... :(
neji
Posts: 155
Joined: Wed Mar 09, 2005 11:39 am
Contact:

Post by neji »

wow thank you "brechi" for this.

Unfortunately I don't know, how to geht the disassembly of the function calls you posted above....

how do I get these using Delphi?
Maybe i can write a simple program which creates the header like that. oO
If somebody is interested in it.
that would be great, some source with comments would be wonderful too :D
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

Hi haventl looked at thw in64 calling convention, ut i have heard that its a little bit like the register conventeion. (Have no win64 yet, maybe in the next weeks)

neji, i have done the disassembling with OllyDbg, but i think madDisAsm should do the same.

You need a program which is using this function. Then u must disassemble it (for RET value checking) and a call of it (ADD ESP, MOV EAX...)

You can do this by hooking the function and looking for the return address to get the call of the function.

Its a little bit tricky.

But if you only have the library (and no program which is using it) you cann do the following:

if it has a PUSH EBP an begining it is 99% cdecl or stdcall convention. So if there is no PUSH EBP -> should be register. THen its hard to see if it has more 0-3 params. If it hast 4 params the RET value is >= 0.
(See the posts above)


The differnce between cdecl and stdcall:
if there is pushed the ebp register at first and then it is used in the code
ex. (MOV EAX, [EBP+8]) then it is a parameter. If the RET value is != 0 then its stdcall convention: RET value div 4 = paramcount.
If the ret value is 0 it can be a stcall vonvention with 0 params or cdecl.
So if (EBP+XXX) is inside the code and RET = 0 then its cdecl convention.
You then need to get the highest EBP value (XXX) subtract 4 and divide it by 4: (XXX-4) div 4. Then you get the paramcount.

Its all a little bit tricky but it works for 90% of functions. All you need is madDisAsm.

Maybe i find some time on weekend for creating an example and looking for win64 convention.

( http://www.freepascal.org/wiki/index.ph ... /AMD64_API ) oO
neji
Posts: 155
Joined: Wed Mar 09, 2005 11:39 am
Contact:

Post by neji »

I tested this with an own function an got this disassembly :

Code: Select all

0049c634    public Unit1.mooh:               ; function entry point
0049c634 56   mov     ecx, $49c654           ; 'asdf'
0049c639      mov     edx, $49c654           ; 'asdf'
0049c63e      mov     eax, [$4a3ddc]
0049c643      call    -$84 ($49c5c4)         ; Unit1.TForm1.foo2
0049c643
0049c648 57   ret
does that mean, that it is the register calling convention because of the filled ecx,eax, edx registers?

and where do I get the Returnadress there?
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

Hi neji its a little bit tricky:

function mooh (0049c634)
function foo2 (0049c5c4)

You can only say 99% what foo2 lookes like. As you has said before, it hast register convention (eax, ebx, ecx is used). And it has 2 params (eax, ebx, ecx, where EAX the first , EBX the second and ECX the third:

We have:

Code: Select all

function foo2(a,b,c: DWord): DWord;
begin
  //
end;
Know we dont know if it is a function or procedure. Because EAX is not used after the call, i would say its a procedure. You can diassemble foo2 and then see if EAX is set in the end of the procedure. But for this example i dont have it. If you dont know if its a procedure or function use it as a function. Then the return value can be right (if its a function). It is wrong if its a procedure but will not be used.

Code: Select all

procedure foo2(a,b,c: DWord);
begin
  //
end;
now we can see that EAX is a global variable. MOV EAX, [global address]

Code: Select all

procedure foo2(a: DWord; b,c: DWord);
begin
  //
end;
and that asdf is a string passed in the second and thir parameter

Code: Select all

procedure foo2(a: Dword; b,c: PChar);
begin
  //
end;
now we look at the mooh function: it must be
1) register convention with < 4 parms
2) cdecl convention
3) stdcall convention with no params

as we can see there is no PUSH EBP at first it seems to be a register convention

because there is NO register used inside the function it has no params

Code: Select all

procedure mooh;
begin
end;
(if ca be

Code: Select all

procedure mooh; stcall;
begin
end;
and

Code: Select all

procedude moog; cdecl;
begin
end;
too, because there is no MOV ... [EBP+xxx], so it has no params for there conventions, too)


if we now put all togehter:

Code: Select all

const text = 'asdf';
var global: Dword; // or other type

procedure foo2(a: Dword; b,c: PChar);
begin
  //
end;

procedure mooh;
begin
  foo2(global,text,text);
end;
some more informations:


because of the Unit1, Tform1 you can see that it is compiled by Borland Delphi XXX

Borland Delphi is using the register convention. That means:

Code: Select all

procedure foo3(a: Dword; b,c: Integer; f: Single);
is the same as

Code: Select all

procedure foo3(a: Dword; b,c: Integer; f: Single);
therefore i knew that its bot register convention ;> But i tried to explain how you can see it if you dont know the compiler or someone is using the stdcall convention inside the delphi code

Code: Select all

procedure foo3(a: Dword; b,c: Integer; f: Single); stdcall;
Now if you dont have a call of the function you want to hook. (Because you have a crypted library with export and a crypted program and you only have the export address, then you can do the following:

Hook the export address with this function:

Code: Select all

var ReturnAddress: DWord;
procedure myCallbackofExportedFunction;
begin
  asm
     PUSH [ESP]
     POP DWORD PTR [ReturnAddress]
  end;
  UnhookTheExportedFunction;
  CreateDisassemblingAndSaveIt(TheExportedFunction);
  CreateDisassemblingAndSaveIt(Pointer(DWord(ReturnAddress)-100));
  ExitProcess(0);
end;
explaination:

if you have a call then the ReturnAddress is on the stack. We get it from there. Now we unhook the function (because there is a jump in there) Its not needed, but we then know if there is a PUSH EBP or something interesting in the first 5/6 bytes.

We disassemble the function (it must be uncrypted now) -> then we can analyse it later.

We disassemble the function which is calling oru fucntion (is inside the executable or other dll which is using the export which we want to analyse)
It is uncrypted, too. We need to analyse it.


I hope this will help you a little bit :>
neji
Posts: 155
Joined: Wed Mar 09, 2005 11:39 am
Contact:

Post by neji »

omg nice work ,thank you.

But I still have some questions :?

in my example foo1 is declared like this :

Code: Select all

procedure foo1(a,b : string);
why are all three registers (eax,ebx,ecx) used in the disassembly , so that it looks like, that the function has three Params instead of two?

When a Function is called, the Returnadress is on the stack right? How can I get this adress using Delphi?
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

Hi neji, that can't be correct.

Code: Select all

procedure foo1(a,b : string);
is using 2 params (EAX, EDX)
you wrote an disassembling with 'foo2' (not 'foo1')

i have tested you code

Code: Select all

procedure foo1(a,b : string); 
with Delphi.
Set a Breakpoint when you are calling it and if it breaks press Crt+Alt+C
Then u see that a,b: string is only using 2 params.

Delphi is using PUSH EBP inside a register call when you use String as param or result. So its not that easy to see the convention, if you dont have the call.

Delphi7:

http://uall.overclock.ch/neji_stringasparam.jpg
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

Ok found it.

Delphi is using 3 params.
The first is the Object!

If you want to hook it you need these 3 params, not the 2 that you used in Delphi.

if you want to hook

Code: Select all

procedure TForm1.Foo1(a,b : string);
begin

end;
you need in your dll:

Code: Select all

procedure Foo1(object: DWord; a,b : string);
begin

end;
So all what i said is about the convention is correct (sometimes delphi is using PUSH EBP for register convention, too)

But if the function is used inside an object, delphi creates a function with 3 params, where the first is the object. Now if you want to hook this function in a library you need exaclty the same paramcount. An this is 3 NOT 2.

http://uall.overclock.ch/neji_objectprocedure.jpg
Post Reply