Page 1 of 3

How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 4:00 am
by leonhardt
procedure pa_begin()
;do something...
endprocedure

procedure pa_end()

endprocedure Then,the size of procedure pa,equals to @pa_and()-@pa_begin? Or else?
In Delphi,I can get the unique function size in that way,how about PB?
I've tested that in two PC,but I' am confused that the value seems uncertain...
then how can I retrieve the function size? I need it to write a process's memory,Thanks!

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 4:12 am
by netmaestro
Just off the top of my head, maybe you could put a label right before EndProcedure and then ?label-@Proc() should be right.

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 4:17 am
by Thorium
You can get the compiled size of a procedure by using labels as start and end marker.

Code: Select all

Procedure Test()

  TestStart:

  ;procedure code here

  TestEnd:

EndProcedure

Test()

Debug ?TestEnd - ?TestStart
Maybe there is some init code befor the start label. But that should do the trick for what ever you want to do.

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 4:37 am
by leonhardt
netmaestro wrote:Just off the top of my head, maybe you could put a label right before EndProcedure and then ?label-@Proc() should be right.
Label doesn't work,I've tried.

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 4:40 am
by leonhardt
Thorium wrote:You can get the compiled size of a procedure by using labels as start and end marker.

Code: Select all

Procedure Test()

  TestStart:

  ;procedure code here

  TestEnd:

EndProcedure

Test()

Debug ?TestEnd - ?TestStart
I wonder whether this method would lose some function entrypoint info or something else?

Maybe there is some init code befor the start label. But that should do the trick for what ever you want to do.

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 5:28 am
by leonhardt
Thorium wrote:You can get the compiled size of a procedure by using labels as start and end marker.

Code: Select all

Procedure Test()

  TestStart:

  ;procedure code here

  TestEnd:

EndProcedure

Test()

Debug ?TestEnd - ?TestStart
Maybe there is some init code befor the start label. But that should do the trick for what ever you want to do.
Here's my code:

Code: Select all

Prototype.l TLoadLib(*LibName.s);map to LoadLibraryA
Prototype.l TGetProc(HLib.l,*ProcName.s); map to GetProcAddress
Prototype.l TMsgBox(hwnd.l,*Text.s,*Caption.s,Flag.l);map to MessageBoxA
EnableExplicit

Structure TParam;parameter structure
fLoad.l
fGetProc.l
fUser.c[15]
fMsg.c[15]
EndStructure

Procedure MyFunc(*p.TParam);remote thread function,no PB commands or strings here,as this function will work in other process
Define MyLoad.TLoadLib
Define MyGet.TGetProc
Define MyMsgBox.TMsgBox
MyLoad=*p\fLoad
MyGet=*p\fGetProc
Define  HLib=MyLoad(@*p\fUser)
MyMsgBox=MyGet(HLib,@*p\fMsg)
MyMsgBox(0,@*p\fUser,@*p\fMsg,0)
FuncEnd:
EndProcedure

Procedure.l funcend()

EndProcedure

Procedure.l EnableDebugPriv();to get the debug privilege 
Define hToken.l,tp.Token_Privileges,rl.l,result=#False;
OpenProcessToken_(GetCurrentProcess_(),#TOKEN_ADJUST_PRIVILEGES |#TOKEN_QUERY,hToken);
   If LookupPrivilegeValue_(#Null, "SeDebugPrivilege", tp\Privileges[0]\Luid)
     tp\PrivilegeCount= 1;
     tp\Privileges[0]\Attributes = #SE_PRIVILEGE_ENABLED;
     If AdjustTokenPrivileges_(hToken, #False, tp,SizeOf(tp), #Null, rl);
     result=#True
     EndIf
   EndIf
ProcedureReturn result
EndProcedure

EnableDebugPriv() 
Define  isize=?funcend-@myfunc();if isize is large enough,such as 555,it works
Define pid.l=3692;a process ID that can be retrieved easily using the taskmanager
;MessageRequester(Str(@myfunc()-@funcend()),"")
Define hprocess= OpenProcess_(#PROCESS_ALL_ACCESS, #False, pid);open process
If hprocess=0
MessageRequester("hprocess=0","")
End
EndIf
Define Hl= GetModuleHandle_("Kernel32.dll");every process must load kernel32.dll
Define param.Tparam
param\fGetProc=GetProcAddress_(Hl,"GetProcAddress");initialize the parameter 
param\fLoad=GetProcAddress_(hl,"LoadLibraryA")
PokeS(@param\fMsg,"MessageBoxA")
PokeS(@param\fUser,"User32.dll")
Define *pparam= VirtualAllocEx_(hprocess, 0, SizeOf(param), #MEM_COMMIT, #PAGE_READWRITE);reserve memory for param
If *pparam=0
MessageRequester("*pparam=0","")
End
EndIf
Define *pfunc= VirtualAllocEx_(hprocess, 0,iSize, #MEM_COMMIT, #PAGE_EXECUTE_READWRITE);reserve memory for the function
If *pfunc=0
MessageRequester("*pfunc=0","")
End
EndIf
Define v.l
Define bw=WriteProcessMemory_(hprocess, *pparam, @param, SizeOf(param), v);write memory
Define bw2=WriteProcessMemory_(hprocess, *pfunc, @MyFunc(), iSize, v);
Define hthread = CreateRemoteThread_(hprocess, 0, 0, *pfunc, *pparam, 0, v);run it 
If hthread=0 
MessageRequester("hthread=0","")
End
EndIf
WaitForSingleObject_(hthread, #INFINITE);
VirtualFreeEx_(hprocess, *pfunc, iSize, #MEM_DECOMMIT);
VirtualFreeEx_(hprocess, *pparam, SizeOf(tparam), #MEM_DECOMMIT);
CloseHandle_(hprocess);
End 
this program creates a remotethread in another process for a test,by showing a messagebox,I used your method,and the messagebox was there,but then the target process crashed, if I define the function size manually to be large enough.for example 555,then everything works correctly,so I just wonder how can I retrieve the actualy function size.

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 11:55 am
by Kaeru Gaman
STRiP
solve the right problem

... you cannot detect the size of an arbitrary function of another process.
find a way to not to need that information.

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 12:35 pm
by leonhardt
Kaeru Gaman wrote:STRiP
solve the right problem

... you cannot detect the size of an arbitrary function of another process.
find a way to not to need that information.
No,I think you should take a look at my code first,I just want to get MY FUNCTION size in order to write it to another process,the function is defined by myself in my code,I should be able to retrieve the size of it,just as I had succeeded in another language such as Delphi.Now I'm trying to implementate that in PB.

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 1:00 pm
by RASHAD
leonhardt Hi
I hope you are not doing something bad
Next piece of code you will get the size of EnableDebugPriv() I think
If it is OK so you can apply the same to any Func.of yours

Code: Select all

Global MyFSize.l

Prototype.l TLoadLib(*LibName.s);map to LoadLibraryA
Prototype.l TGetProc(HLib.l,*ProcName.s); map to GetProcAddress
Prototype.l TMsgBox(hwnd.l,*Text.s,*Caption.s,Flag.l);map to MessageBoxA
EnableExplicit

Structure TParam;parameter structure
fLoad.l
fGetProc.l
fUser.c[15]
fMsg.c[15]
EndStructure

Procedure MyFunc(*p.TParam);remote thread function,no PB commands or strings here,as this function will work in other process
Define MyLoad.TLoadLib
Define MyGet.TGetProc
Define MyMsgBox.TMsgBox
MyLoad=*p\fLoad
MyGet=*p\fGetProc
Define  HLib=MyLoad(@*p\fUser)
MyMsgBox=MyGet(HLib,@*p\fMsg)
MyMsgBox(0,@*p\fUser,@*p\fMsg,0)
EndProcedure

Procedure.l funcend()

EndProcedure

Procedure.l EnableDebugPriv();to get the debug privilege 
FuncStart:
Define hToken.l,tp.Token_Privileges,rl.l,result=#False;
OpenProcessToken_(GetCurrentProcess_(),#TOKEN_ADJUST_PRIVILEGES |#TOKEN_QUERY,hToken);
   If LookupPrivilegeValue_(#Null, "SeDebugPrivilege", tp\Privileges[0]\Luid)
     tp\PrivilegeCount= 1;
     tp\Privileges[0]\Attributes = #SE_PRIVILEGE_ENABLED;
     If AdjustTokenPrivileges_(hToken, #False, tp,SizeOf(tp), #Null, rl);
     result=#True
     EndIf
   EndIf
FuncEnd:
MyFSize = ?FuncEnd - ?FuncStart
ProcedureReturn result
EndProcedure

EnableDebugPriv()
MessageRequester("MyFunc Size",Str(MyFSize))
 
Define  isize=?funcend-@myfunc();if isize is large enough,such as 555,it works
Define pid.l=3692;a process ID that can be retrieved easily using the taskmanager
;MessageRequester(Str(@myfunc()-@funcend()),"")
Define hprocess= OpenProcess_(#PROCESS_ALL_ACCESS, #False, pid);open process
If hprocess=0
MessageRequester("hprocess=0","")
End
EndIf
Define Hl= GetModuleHandle_("Kernel32.dll");every process must load kernel32.dll
Define param.Tparam
param\fGetProc=GetProcAddress_(Hl,"GetProcAddress");initialize the parameter 
param\fLoad=GetProcAddress_(hl,"LoadLibraryA")
PokeS(@param\fMsg,"MessageBoxA")
PokeS(@param\fUser,"User32.dll")
Define *pparam= VirtualAllocEx_(hprocess, 0, SizeOf(param), #MEM_COMMIT, #PAGE_READWRITE);reserve memory for param
If *pparam=0
MessageRequester("*pparam=0","")
End
EndIf
Define *pfunc= VirtualAllocEx_(hprocess, 0,iSize, #MEM_COMMIT, #PAGE_EXECUTE_READWRITE);reserve memory for the function
If *pfunc=0
MessageRequester("*pfunc=0","")
End
EndIf
Define v.l
Define bw=WriteProcessMemory_(hprocess, *pparam, @param, SizeOf(param), v);write memory
Define bw2=WriteProcessMemory_(hprocess, *pfunc, @MyFunc(), iSize, v);
Define hthread = CreateRemoteThread_(hprocess, 0, 0, *pfunc, *pparam, 0, v);run it 
If hthread=0 
MessageRequester("hthread=0","")
End
EndIf
WaitForSingleObject_(hthread, #INFINITE);
VirtualFreeEx_(hprocess, *pfunc, iSize, #MEM_DECOMMIT);
VirtualFreeEx_(hprocess, *pparam, SizeOf(tparam), #MEM_DECOMMIT);
CloseHandle_(hprocess);
End

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 1:11 pm
by srod
The label at the end of the function does not actually mark the end of the function because there will be 'tidy up' code and stack clean-up code added after the label. You can see this by looking at some ASM generated by the compiler.

Putting labels outside of the Procedure / EndProcedure block will not work because the compiler embeds each procedure within an ASM macro and invokes the macro only if the compiler decides that the procedure is actually called from somewhere in the program etc.

What you can do is use a dummy procedure to mark the end of the funtion you are interested in as with the following :

Code: Select all

Procedure.i test1(a)
  a + 1
  ProcedureReturn a
EndProcedure

Procedure zum1()
EndProcedure

sizeOfTest1 = @zum1() - @test1()

Debug sizeOfTest1
In this case, the macro invokations which add the two procedures to the ASM are conseuctive and so the code would appear correct.

This does give some strange results though! Although no stranger than the following in which label2 and label1 seem to be separated by 19 bytes on my system! Why is that?

Code: Select all

Procedure.i test1(a)
label1:
  a + 1
label2:
  ProcedureReturn a
EndProcedure

Debug ?label2 - ?label1
I think that @zum1() - @test1() in the example above should give a result which is certainly no smaller than the required result. Quite why I am getting some bazaar results escapes me at the moment? Alignment perhaps?

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 1:18 pm
by RASHAD
Yes I know that there is still ProcedureReturn result
But may be he can add some bytes = The last code
Or use your approach
Or somebody can come with a new shot

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 1:22 pm
by srod
No there can be quite a lot of code added; especially in cases where the procedure uses strings and/or arrays.

E.g. the following :

Code: Select all

Procedure.i test1(a)
  Dim a(10)
  a$ = "Hello"
  b$ = "Hello"
  ProcedureReturn 0
  l1:
EndProcedure
produces :

Code: Select all

; Procedure.i test1(a)
macro MP0{
_Procedure0:
  PS0=20
  XOR    eax,eax
  PUSH   eax
  PUSH   eax
  PUSH   eax
  PUSH   eax                                                                                                                                                                                              
; Dim a(10)
  PUSH   dword 21
  LEA    edx,[esp+4]
  PUSH   edx
  PUSH   dword 0
  MOV    edx,dword [esp+12]
  CALL   SYS_FreeArray
  MOV    eax,11
  PUSH   dword 4
  CALL   SYS_AllocateArray
; a$ = "Hello"
  MOV    edx,_S1
  LEA    ecx,[esp+8]
  CALL   SYS_FastAllocateStringFree
; b$ = "Hello"
  MOV    edx,_S1
  LEA    ecx,[esp+12]
  CALL   SYS_FastAllocateStringFree
; ProcedureReturn 0
  XOR    eax,eax
  JMP   _EndProcedure1
; l1:
l_l1:
; EndProcedure
  XOR    eax,eax
_EndProcedure1:
  PUSH   dword [esp+8]
  CALL  _SYS_FreeString@4
  PUSH   dword [esp+12]
  CALL  _SYS_FreeString@4
  PUSH   eax
  MOV    edx,dword [esp+4]
  CALL   SYS_FreeArray
  POP    eax
  ADD    esp,16
  RET    4
}
Just look how much code comes after the label!

You cannot easily predict just how many 'extra bytes' you will need to add.

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 1:25 pm
by RASHAD
OK you proved it
No more talk about that method

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 2:30 pm
by leonhardt
srod wrote:No there can be quite a lot of code added; especially in cases where the procedure uses strings and/or arrays.

E.g. the following :

Code: Select all

Procedure.i test1(a)
  Dim a(10)
  a$ = "Hello"
  b$ = "Hello"
  ProcedureReturn 0
  l1:
EndProcedure
produces :

Code: Select all

; Procedure.i test1(a)
macro MP0{
_Procedure0:
  PS0=20
  XOR    eax,eax
  PUSH   eax
  PUSH   eax
  PUSH   eax
  PUSH   eax                                                                                                                                                                                              
; Dim a(10)
  PUSH   dword 21
  LEA    edx,[esp+4]
  PUSH   edx
  PUSH   dword 0
  MOV    edx,dword [esp+12]
  CALL   SYS_FreeArray
  MOV    eax,11
  PUSH   dword 4
  CALL   SYS_AllocateArray
; a$ = "Hello"
  MOV    edx,_S1
  LEA    ecx,[esp+8]
  CALL   SYS_FastAllocateStringFree
; b$ = "Hello"
  MOV    edx,_S1
  LEA    ecx,[esp+12]
  CALL   SYS_FastAllocateStringFree
; ProcedureReturn 0
  XOR    eax,eax
  JMP   _EndProcedure1
; l1:
l_l1:
; EndProcedure
  XOR    eax,eax
_EndProcedure1:
  PUSH   dword [esp+8]
  CALL  _SYS_FreeString@4
  PUSH   dword [esp+12]
  CALL  _SYS_FreeString@4
  PUSH   eax
  MOV    edx,dword [esp+4]
  CALL   SYS_FreeArray
  POP    eax
  ADD    esp,16
  RET    4
}
Just look how much code comes after the label!

You cannot easily predict just how many 'extra bytes' you will need to add.
Well, I think you're right,using a dummy procedure maybe the only way,thank you all guys. :)

Re: How to retrieve the size of a procedure?

Posted: Thu Jan 14, 2010 4:49 pm
by Demivec
srod wrote:I think that @zum1() - @test1() in the example above should give a result which is certainly no smaller than the required result. Quite why I am getting some bazaar results escapes me at the moment? Alignment perhaps?
@srod: regarding the possible reasons for your bazaar results, your examples include the debugger code woven around your desired code. Your example shows 85 bytes for me (with Win XP) with debugger but only 17 without debugger (using MessageRequester() ).