the magic of ImportC is able to provide us with functions not present in the API that PB recognizes by default.
ptrace() allows a user to attach to a process in order to peek and poke (read and inject) into it.
The following code attaches to a running process and reads the contents of its data section (entailed from the /proc/ pseudofiles), then displays a chunk of it in a gadget.
Note: the program needs to be fed the PID of the to be debugged process. In the following code, pls set the 'pid' variable accordingly | add a ProgramParameter() accordingly etc.
Code: Select all
pid = 6200 ; !!!! PROCESS TO ATTACH TO !!!!
;{ PTRACE CONSTANTS
#PTRACE_TRACEME = 0 ; Indicate that the process making this request should be traced. All signals received by this process can be intercepted by its parent, And its parent can use the other `ptrace' requests.
#PTRACE_PEEKTEXT = 1 ; Return the word in the process's text space at address ADDR.
#PTRACE_PEEKDATA = 2 ; Return the word in the process's data space at address ADDR.
#PTRACE_PEEKUSER = 3 ; Return the word in the process's user area at offset ADDR.
#PTRACE_POKETEXT = 4 ; Write the word DATA into the process's text space at address ADDR.
#PTRACE_POKEDATA = 5 ; Write the word DATA into the process's data space at address ADDR.
#PTRACE_POKEUSER = 6 ; Write the word DATA into the process's user area at offset ADDR.
#PTRACE_CONT = 7 ; Continue the process.
#PTRACE_KILL = 8 ; Kill the process.
#PTRACE_SINGLESTEP = 9 ; Single step the process. This is not supported on all machines.
#PTRACE_GETREGS = 12 ; Get all general purpose registers used by a processes. This is not supported on all machines.
#PTRACE_SETREGS = 13 ; Set all general purpose registers used by a processes. This is not supported on all machines.
#PTRACE_GETFPREGS = 14 ; Get all floating point registers used by a processes. This is not supported on all machines.
#PTRACE_SETFPREGS = 15 ; Set all floating point registers used by a processes. This is not supported on all machines.
#PTRACE_ATTACH = 16 ; Attach to a process that is already running.
#PTRACE_DETACH = 17 ; Detach from a process attached to with PTRACE_ATTACH.
#PTRACE_GETFPXREGS = 18 ; Get all extended floating point registers used by a processes. This is not supported on all machines.
#PTRACE_SETFPXREGS = 19 ; Set all extended floating point registers used by a processes. This is not supported on all machines.
#PTRACE_SYSCALL = 24 ; Continue and stop at the next (return from) syscall.
#PTRACE_SETOPTIONS = $4200 ; Set ptrace filter options.
#PTRACE_GETEVENTMSG = $4201 ; Get last ptrace message.
#PTRACE_GETSIGINFO = $4202 ; Get siginfo For process.
#PTRACE_SETSIGINFO = $4203 ; Set new siginfo for process.
;}
ImportC ""
ptrace(request, pid, *paddr, *pdata )
EndImport
Procedure Hex2Val( h.s )
h=UCase(h) : c=0
b=PeekB(@h) : m=Pow(16,Len(h)-1) : Repeat
If b>64 : b-7 : EndIf
b-48
v=v+(m*b) : m/16
c+1 : b=PeekB(@h+c)
Until b=0
ProcedureReturn v
EndProcedure
Procedure.s GetShellOutput( cmd.s )
prg = RunProgram("sh","-c "+#DQUOTE$+cmd+#DQUOTE$,"",#PB_Program_Open|#PB_Program_Read)
If prg
While ProgramRunning(prg) ;And AvailableProgramOutput(prg)
out.s=out+ReadProgramString(prg)+#LF$
Wend
EndIf
ProcedureReturn out
EndProcedure
Procedure GetMemoryMap( pid , *mstart.long , *mend.long )
s.s = GetShellOutput("ls -l /proc/"+Str(pid)+"/exe") : p = FindString(s," -> ",1)
exefullpath.s = Trim(Right(s,Len(s)-p-4))
s = GetShellOutput("cat /proc/"+Str(pid)+"/maps | grep rwxp | grep "+exefullpath)
s = StringField(s,1," ")
*mstart\l = Hex2Val(StringField(s,1,"-"))
*mend\l = Hex2Val(StringField(s,2,"-"))
ProcedureReturn *mstart\l
EndProcedure
Procedure FillPtraceBuffer( *mem.ascii , pid , mstart , mend )
err = ptrace( #PTRACE_ATTACH , pid ,0,0) : Delay(10)
If err=0
For a=mstart To mend-1
by.a=ptrace( #PTRACE_PEEKDATA , pid , a , 0 )
*mem\a=by : *mem+1
Next
ptrace( #PTRACE_DETACH , pid ,0,0) : Delay(10)
Else
Debug "Can't attach!"
EndIf
EndProcedure
Procedure UpdateMemoryView( gad , *mem.ascii , startaddr )
s.s="" : wl=60 : ww=512
For a=0 To ww-1
If Len(s)%wl=0 : s=s+"."+RSet(Hex(startaddr,#PB_Long),8,"0")+" " : startaddr+16 : EndIf
s = s+RSet(Hex(*mem\a,#PB_Byte),3) : *mem+1
If Len(s)%wl=59 : s=s+#LF$ : EndIf
Next
SetGadgetText(gad,s)
EndProcedure
ms.l : me.l : GetMemoryMap(pid,@ms,@me) : ml = me-mf
ptrc_buf = AllocateMemory(ml)
If OpenWindow(0,0,0,400,600,"Ptrace Example")
EditorGadget(0,0,0,400,600)
LoadFont(0,"Monospace",8) : SetGadgetFont(0,FontID(0))
AddWindowTimer(0,1,500)
Else : End : EndIf
Repeat
EvID=WaitWindowEvent()
Select EvID
Case #PB_Event_Timer
FillPtraceBuffer( ptrc_buf , pid , ms , me )
UpdateMemoryView( 0 , ptrc_buf , ms )
EndSelect
Until EvID=#PB_Event_CloseWindow
Doubtful as an implementation as it is, the above works.