JustAGuy Posted July 4, 2015 Posted July 4, 2015 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.
kao Posted July 4, 2015 Posted July 4, 2015 (edited) 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 July 4, 2015 by kao
kao Posted July 4, 2015 Posted July 4, 2015 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.
JustAGuy Posted July 4, 2015 Author Posted July 4, 2015 (edited) 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 July 4, 2015 by JustAGuy
kao Posted July 4, 2015 Posted July 4, 2015 Let's look at it from the another perspective - why do you need it? An why is approximate size not good enough for you?
n0th!ng Posted July 4, 2015 Posted July 4, 2015 (edited) 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 July 4, 2015 by n0th!ng
evlncrn8 Posted July 4, 2015 Posted July 4, 2015 because ret instruction isnt always 0xc3.. and what if you have mov eax, 0c3c3c3c3h ?
JustAGuy Posted July 4, 2015 Author Posted July 4, 2015 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
JustAGuy Posted July 4, 2015 Author Posted July 4, 2015 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
LCF-AT Posted July 4, 2015 Posted July 4, 2015 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 0x10On 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
Alzri2 Posted July 4, 2015 Posted July 4, 2015 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). 1
Gyrus Posted July 5, 2015 Posted July 5, 2015 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; GetProcSize.rar 1
Gyrus Posted July 5, 2015 Posted July 5, 2015 @Alzri2 mov r/m, eip or mov eip, r/mis 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). 1
Alzri2 Posted July 5, 2015 Posted July 5, 2015 @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
Alzri2 Posted July 5, 2015 Posted July 5, 2015 Why not ?I think the stack is dealt with safely in this one.
JustAGuy Posted July 6, 2015 Author Posted July 6, 2015 for those of you interested I solved EIP problem this way @a1: lea eax,[@a1] mov _end, eax
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now