How to retrieve the size of a procedure?

Just starting out? Need help? Post your questions and find answers here.
User avatar
leonhardt
Enthusiast
Enthusiast
Posts: 220
Joined: Wed Dec 23, 2009 3:26 pm

How to retrieve the size of a procedure?

Post 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!
poor English...

PureBasic & Delphi & VBA
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: How to retrieve the size of a procedure?

Post 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.
BERESHEIT
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: How to retrieve the size of a procedure?

Post 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.
User avatar
leonhardt
Enthusiast
Enthusiast
Posts: 220
Joined: Wed Dec 23, 2009 3:26 pm

Re: How to retrieve the size of a procedure?

Post 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.
poor English...

PureBasic & Delphi & VBA
User avatar
leonhardt
Enthusiast
Enthusiast
Posts: 220
Joined: Wed Dec 23, 2009 3:26 pm

Re: How to retrieve the size of a procedure?

Post 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.
poor English...

PureBasic & Delphi & VBA
User avatar
leonhardt
Enthusiast
Enthusiast
Posts: 220
Joined: Wed Dec 23, 2009 3:26 pm

Re: How to retrieve the size of a procedure?

Post 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.
poor English...

PureBasic & Delphi & VBA
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Re: How to retrieve the size of a procedure?

Post 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.
oh... and have a nice day.
User avatar
leonhardt
Enthusiast
Enthusiast
Posts: 220
Joined: Wed Dec 23, 2009 3:26 pm

Re: How to retrieve the size of a procedure?

Post 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.
poor English...

PureBasic & Delphi & VBA
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: How to retrieve the size of a procedure?

Post 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
Egypt my love
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: How to retrieve the size of a procedure?

Post 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?
I may look like a mule, but I'm not a complete ass.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: How to retrieve the size of a procedure?

Post 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
Egypt my love
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: How to retrieve the size of a procedure?

Post 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.
I may look like a mule, but I'm not a complete ass.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: How to retrieve the size of a procedure?

Post by RASHAD »

OK you proved it
No more talk about that method
Egypt my love
User avatar
leonhardt
Enthusiast
Enthusiast
Posts: 220
Joined: Wed Dec 23, 2009 3:26 pm

Re: How to retrieve the size of a procedure?

Post 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. :)
poor English...

PureBasic & Delphi & VBA
User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: How to retrieve the size of a procedure?

Post 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() ).
Post Reply