Jump to content
Tuts 4 You

size of the code after compilation


JustAGuy

Recommended Posts

Hi, is it possible somehow to get size or end address of a procedure, preferably without modifying procedure itself?


 


e.g:


 




Procedure Asem;
begin
asm
mov eax, 5;
add eax,8
shl eax,1
end;
end;

I want from my application determine size(number of  bytes) of its own procedure, let's say, when I press a button. It's quite easy by using pointers to get start address of first line mov eax, 5, but how to get address of the last line(eventually RET)? For the sake of simplicity let's say the procedure is pretty simple with only one exit point and no external jumps outside of itself.


 


 



 

Link to comment

For sake of simplicity, use address of first byte of the next procedure.



{$APPTYPE CONSOLE}
uses Windows, Classes, Sysutils;
 
Procedure Asem;
begin
asm
 mov eax, 5;
 add eax,8
 shl eax,1
end;
end;
 
Procedure Bla;
begin
   Writeln('whatever');
end;
 
begin
   Writeln(Format('start of Asem: 0x%x', [dword(@Asem)]));
   Writeln(Format('start of next proc: 0x%x', [dword(@Bla)]));
   Writeln(Format('approximate size of Asem: 0x%x', [dword(@Bla)-dword(@Asem)]));
end.

Edited by kao
Link to comment

Well, unless you want to use some disassembly engine (BeaEngine/Capstone/etc.) that's the best I can think of.


Borland's inline assembler is too limited to do anything better.


Link to comment

Would it help if the procedure was pure delphi/pascal instead of assembler?


Only solution I came up with is to compile some markers in $I directive, but that's not a very clever solution........ scanning a file


Edited by JustAGuy
Link to comment

Let's look at it from the another perspective - why do you need it? An why is approximate size not good enough for you?


Link to comment

so why don't you keep reading byte from memory until ret instruction(it is better to use TitanEngine...etc)



program Project2; {$APPTYPE CONSOLE} uses
SysUtils,Windows;
function GetSize(Address:Pointer):Cardinal;
var
C3:Byte;
tempaddress:Cardinal;
i:integer;
begin
i:=0;
tempaddress:=Cardinal(Address);
while(not(C3 = $C3)) do
begin
i:=i+1;
CopyMemory(@C3,ptr(tempaddress+i),1);
end;
result:=i+1;
end; Procedure Asem;
begin
asm
mov eax, 5;
add eax,8
shl eax,1
end;
end; begin
Writeln(Format('%p',[@Asem]));
Writeln(Format('%d',[GetSize(@Asem)]));
Readln;
end.

Edited by n0th!ng
Link to comment

kao;  to get binary part of code I write without  tedious manual extraction


 


n0th!ng: thank you, but I did want to do it with search I was hoping to find some neat solution , but there probably is not any


Link to comment

because ret instruction isnt always 0xc3.. and what if you have mov eax, 0c3c3c3c3h ?

 

also it would cause trouble if there were more than one 0xc3

Link to comment

Hi,


 


so if I do understand you correctly then you want to find out any entire routine size lenght of your own coded source right?If you don't wanna find out each size lenght of all commands etc and you only wanna have routine entry / end then just log them both in your own table somewhere.



01020000 00401035 Routine Start
01020004 00401400 Routine End 00401035 PUSH EBP
......................
00401400 MOV EAX,0x1
00401405 LEAVE
00401406 RETN 0x10

On the other hand if your routine used more end outputs (more than only one) then you need to log them too.Or you do write some static code into each routine like this...



00401000 > E8 00000000 CALL 00401005
00401005 5F POP EDI
00401006 83EF 05 SUB EDI,0x5 ; top in edi
00401009 90 NOP
0040100A 90 NOP
0040100B 90 NOP
0040100C 90 NOP
0040100D 90 NOP
0040100E 90 NOP
0040100F 90 NOP
00401010 E8 00000000 CALL 00401015
00401015 5E POP ESI
00401016 2BF7 SUB ESI,EDI ; = lenght
00401018 83C6 07 ADD ESI,0x7 ; + add till ret
0040101B C3 RETN

= 1C lenght.Maybe you do something like this.All in all I think its not so easy to get the entire routine lenght without to check all possibly dynamic commands + to follow them to find all ends & real end of routine if its using a real end.Some don't use returns so this can also be dynamic (just a example if you also wanna check unknown codes).If you only wanna check this with your own codes then use only one routine output and log them all and sub the top from the end = size of routine.No idea what you do plan to do later with that infos or for what it should be important etc.


 


greetz


Link to comment

If you want to get the size after the procedure gets executed, you can use EIP to save the address at the very end of it (so u can easily calculate the size).



begin
asm
mov eax, 5;
add eax,8
shl eax,1
mov dword ptr [var], eip
end;
end;

Otherwise, u've gotta search for RET(C3).


  • Like 1
Link to comment
I think using nested routines and labels can solve your issue.



procedure TForm1.Button2Click(Sender: TObject);
label _end;
var
  pStart : Pointer;
  pEnd : Pointer;
  procedure myproc;
  begin
    asm //Dummy code:
      pushad
      mov eax, 5
      add eax, 6
      shl eax, 1
      mov eax, ebx
      pop dword ptr ss:[esp]
      sub esp, 4
      popad
    _end:
    end;
  end;
begin
  pStart := @myproc;
  lstLog.AddItem('Start = 0x' + IntToHex(DWORD(pStart), 8), Sender);
  asm
    push eax
    lea eax, _end //label points to 1 byte further than real end point.
    mov pEnd, eax
    pop eax
  end;
  lstLog.AddItem('End = 0x' + IntToHex(DWORD(pEnd), 8), Sender);   lstLog.AddItem('myproc size = 0x' + IntToHex(DWORD(pEnd) - DWORD(pStart) - 1, 8), Sender);
end;


post-88645-0-89618500-1436094971.png


 


GetProcSize.rar


  • Like 1
Link to comment

@Alzri2



mov r/m, eip
or
mov eip, r/m

is not possible.


 


From Intel® 64 and IA-32 Architectures Software Developer’s Manual (2015) :


 





The processor fetches instructions from the code segment, using a logical address that consists of the segment selector in the CS register and the contents of the EIP register. The EIP register contains the offset within the code segment of the next instruction to be executed. The CS register cannot be loaded explicitly by an application program. Instead, it is loaded implicitly by instructions or internal processor operations that change program control (such as, procedure calls, interrupt handling, or task switching).




 


The EIP register cannot be accessed directly by software; it is controlled implicitly by control-transfer instructions (such as JMP, Jcc, CALL, and RET), interrupts, and exceptions. The only way to read the EIP  register is to execute a CALL instruction and then read the value of the return instruction pointer from the procedure stack. The EIP register can be loaded indirectly by modifying the value of a return instruction pointer on the procedure stack and executing a return instruction (RET or IRET).




 


  • Like 1
Link to comment

@Gyrus:


You're right, I forgot about the limitations of accessing EIP reg :)


As an alternative, I tried this (don't have delphi to make an example):



.data
vEIP dd ? .code
start:
call GetEIP invoke ExitProcess, 0 GetEIP proc
push [esp]
pop [vEIP]
ret
GetEIP endp end start
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...