intercept API

Just starting out? Need help? Post your questions and find answers here.
User avatar
Michael Vogel
Addict
Addict
Posts: 2582
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: intercept API

Post by Michael Vogel »

DarkDragon wrote:Well I've done a hooking-code which works on Windows 7 x64 compiled with 64bit and 32bit. It is basic hooking and uses the disassembler of purebasic, which sometimes really works wrong. And you can't call the old method at the moment.

http://www.bradan.eu/files/hook.zip (Your antivirus will recognize it as a virus, sorry)
I had a working tool to debug network traffic for a network game written in purebasic (4.x), but meantime (windows 8.1 instead of xp, purebasic version 5+) it doesn't work anymore...
...so I try to find an alternative to write a log file showing the network data of the program. I tried to modify your code but I wasn't able to hook the winsock functions receive and send...

TestDll.dll:

Code: Select all


#HookMessages=	0
#HookWinsock=	1

; Define

	Declare MessageBoxAHook(Parent.i,*Text,*Title,Type.i)
	Declare WinsockSend(s.l,*buf,len.l,flags.l)
	Declare WinsockRecv(s.l,*buf,len.l,flags.l)

	Structure SFunction
		*OldAddress
		*NewAddress
		*Buffer
		BufferSize.i
		OldProtect.i
	EndStructure

	Global NewList Functions.SFunction()
	Global *WinsockSend
	Global *WinsockRecv
	Global Logging

	Procedure.s Disassemble(*Buffer,Length)
		Protected Result.s=""

		If ExamineAssembly(*Buffer,*Buffer+Length)
			Result=""
			While NextInstruction()
				If FindString(LCase(InstructionString()),"invalid",1) <= 0
					Result+InstructionString()+#CRLF$
				EndIf
			Wend
		EndIf

		ProcedureReturn Result
	EndProcedure
	Procedure.s HexMemory(*Buffer,Length)

		Protected k.i
		Protected Result.s=""

		For k=0 To Length-1
			Result+RSet(Hex(PeekA(*Buffer+k),#PB_Ascii),2,"0")+" "
		Next k

		ProcedureReturn Result

	EndProcedure
	Procedure Hook(*OldAddress,*NewAddress)

		Protected ProcessHandle.i
		Protected MemoryInfo.MEMORY_BASIC_INFORMATION
		Protected Length.i
		Protected i.i
		Protected Bytes.i
		Protected Disassembly.s
		Protected OldDisassembly.s

		CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
			Protected JMP.u=$E0FF
			Protected MOV.u=$B848
		CompilerElse
			Protected JMP.u=$E0FF
			Protected MOV.a=$B8
		CompilerEndIf
		Protected NOP.a=$90
		Protected JumpAddress.i

		ProcessHandle=OpenProcess_(#PROCESS_ALL_ACCESS,#False,GetCurrentProcessId_())
		If ProcessHandle
			AddElement(Functions())
			Functions()\OldAddress=*OldAddress
			Functions()\NewAddress=*NewAddress
			Functions()\Buffer=AllocateMemory(64)

			VirtualQuery_(Functions()\OldAddress,@MemoryInfo,SizeOf(MEMORY_BASIC_INFORMATION))
			VirtualProtect_(MemoryInfo\BaseAddress,MemoryInfo\RegionSize,#PAGE_EXECUTE_READWRITE,@Functions()\OldProtect)

			; read the memory block
			Length=SizeOf(JumpAddress)+SizeOf(JMP)+SizeOf(MOV)-1
			ReadProcessMemory_(ProcessHandle,Functions()\OldAddress,Functions()\Buffer,Length,@Bytes)
			Disassembly=Disassemble(Functions()\Buffer,Length)
			OldDisassembly=Disassembly
			While Length <= MemorySize(Functions()\Buffer) And OldDisassembly=Disassembly
				Length+1
				ReadProcessMemory_(ProcessHandle,Functions()\OldAddress,Functions()\Buffer,Length,@Bytes)

				OldDisassembly=Disassembly
				Disassembly=Disassemble(Functions()\Buffer,Length)
			Wend

			Functions()\Buffer=ReAllocateMemory(Functions()\Buffer,Length)
			Functions()\BufferSize=Length

			; write our jump command to it
			JumpAddress=Functions()\NewAddress

			i=0
			WriteProcessMemory_(ProcessHandle,Functions()\OldAddress,@MOV,SizeOf(MOV),@Bytes)
			i+SizeOf(MOV)

			WriteProcessMemory_(ProcessHandle,Functions()\OldAddress+i,@JumpAddress,SizeOf(JumpAddress),@Bytes)
			i+SizeOf(JumpAddress)

			WriteProcessMemory_(ProcessHandle,Functions()\OldAddress+i,@JMP,SizeOf(JMP),@Bytes)
			i+SizeOf(JMP)

			; fill the rest with NOP
			While i < Functions()\BufferSize
				WriteProcessMemory_(ProcessHandle,Functions()\OldAddress+i,@NOP,1,@Bytes)
				i+1
			Wend

			; debug it
			*Buffer=AllocateMemory(SizeOf(JumpAddress)+5)
			ReadProcessMemory_(ProcessHandle,Functions()\OldAddress,*Buffer,SizeOf(JumpAddress)+5,@Bytes)
			CloseHandle_(ProcessHandle)
		EndIf

	EndProcedure
	Procedure Unhook(*NewAddress)
		Protected Result=#False
		Protected ProcessHandle.i
		Protected MemoryInfo.MEMORY_BASIC_INFORMATION
		Protected Protection.i
		Protected Bytes.i

		ForEach Functions()
			If Functions()\NewAddress=*NewAddress
				ProcessHandle=OpenProcess_(#PROCESS_ALL_ACCESS,#False,GetCurrentProcessId_())
				If ProcessHandle <> 0
					WriteProcessMemory_(ProcessHandle,Functions()\OldAddress,Functions()\Buffer,Functions()\BufferSize,@Bytes)

					VirtualQuery_(Functions()\OldAddress,@MemoryInfo,SizeOf(MEMORY_BASIC_INFORMATION))
					VirtualProtect_(MemoryInfo\BaseAddress,MemoryInfo\RegionSize,Functions()\OldProtect,@Protection)

					DeleteElement(Functions())
					Result=#True

					CloseHandle_(ProcessHandle)
				EndIf
				Break
			EndIf
		Next

		ProcedureReturn Result
	EndProcedure

	ProcedureDLL AttachProcess(Instance)
		
		; MessageRequester("Start",Str(Instance))

		Protected *OldAddress
		Protected *NewAddress

		CompilerIf #HookMessages
			Library=OpenLibrary(#PB_Any,"user32.dll")
			If Library
				*OldAddress=GetFunction(Library,"MessageBoxA")
				*NewAddress=@MessageBoxAHook()
				If *OldAddress And *NewAddress
					;MessageRequester("!","Message hooked")
					Hook(*OldAddress,*NewAddress)
				EndIf
				CloseLibrary(Library)
			EndIf
		CompilerEndIf

		CompilerIf #HookWinsock
			Library=LoadLibrary_("wsock32.dll")
			If Library
				MessageRequester("...",Str(Library))
				*WinsockSend=GetFunction(Library,"send")
				*WinsockRecv=GetFunction(Library,"recv")

				If *WinsockSend And *WinsockRecv
					*NewAddress=@WinsockSend()
					If *NewAddress
						Hook(*WinsockSend,*NewAddress)
						MessageRequester("Send hooked",Str(*WinsockSend)+#CR$+Str(*NewAddress))
					EndIf

					*NewAddress=@WinsockRecv()
					If *NewAddress
						Hook(*WinsockRecv,*NewAddress)
						MessageRequester("Receive hooked",Str(*WinsockRecv)+#CR$+Str(*NewAddress))
					EndIf
				EndIf

			EndIf

			If OpenFile(0,"Sniffer.log")
				Logging=#True
			EndIf
		CompilerEndIf

	EndProcedure
	ProcedureDLL DetachProcess(Instance)

		Unhook(@MessageBoxAHook())

		If Logging
			CloseFile(0)
		EndIf

	EndProcedure

; EndDefine

ProcedureDLL WinsockSend(s.l,*buf,len.l,flags.l)

	Result.l=CallFunctionFast(*WinsockSend,s.l,*buf,len.l,flags.l)

	If Logging
		WriteString(0,"> ")
		WriteData(0,*buf,len)
		WriteStringN(0,"")
	EndIf

	ProcedureReturn Result

EndProcedure
ProcedureDLL WinsockRecv(s.l,*buf,len.l,flags.l)

	Result.l = CallFunctionFast(*WinsockRecv,s.l,*buf,len.l,flags.l)

	If Logging
		WriteStringN(0, "< ")
		WriteData(0,*buf,len)
		WriteStringN(0,"")
	EndIf

	ProcedureReturn Result

EndProcedure
ProcedureDLL MessageBoxAHook(Parent.i,*Text,*Title,Type.i)

	Protected Window

	Window=OpenWindow(#PB_Any,0,0,320,240,"Information",#PB_Window_SystemMenu | #PB_Window_TitleBar,Parent)

	TextGadget(#PB_Any,10,10,300,220,"Hooked!")

	Repeat : Until WaitWindowEvent(5)=#PB_Event_CloseWindow
	CloseWindow(Window)

EndProcedure

TryMe.exe:

Code: Select all

Procedure InjectLibary(ProcessID.i, Library.s)
	Protected ProcessHandle.i = 0
	Protected ThreadHandle.i = 0
	Protected *FilenameExtern
	Protected *FilenameIntern
	Protected KernelLibrary.i = 0
	Protected *LoadLibraryA = #Null
	Protected Result.i = #False

	ProcessHandle = OpenProcess_(#PROCESS_QUERY_INFORMATION | #PROCESS_CREATE_THREAD | #PROCESS_VM_OPERATION | #PROCESS_VM_WRITE, 0, ProcessID)

	If ProcessHandle = 0
		ProcedureReturn #False
	EndIf

	Size = StringByteLength(Library, #PB_Ascii) + 1
	If Size <= 0
		CloseHandle_(ProcessHandle)
		ProcedureReturn #False
	EndIf

	*FilenameExtern = VirtualAllocEx_(ProcessHandle, #Null, Size, #MEM_COMMIT, #PAGE_READWRITE)
	*FilenameIntern = AllocateMemory(Size)

	If *FilenameIntern <> #Null And *FilenameExtern <> #Null
		PokeS(*FilenameIntern, Library, -1, #PB_Ascii)

		If WriteProcessMemory_(ProcessHandle, *FilenameExtern, *FilenameIntern, Size, #Null) <> 0
			KernelLibrary = OpenLibrary(#PB_Any, "kernel32.dll")
			If KernelLibrary
				*LoadLibraryA = GetFunction(KernelLibrary, "LoadLibraryA")
				CloseLibrary(KernelLibrary)
			EndIf

			If *LoadLibraryA <> #Null
				ThreadHandle = CreateRemoteThread_(ProcessHandle, #Null, #Null, *LoadLibraryA, *FilenameExtern, #Null, #Null)

				If ThreadHandle <> 0
					WaitForSingleObject_(ThreadHandle, #INFINITE)

					Result = #True

					CloseHandle_(ThreadHandle)
					ThreadHandle = 0
				EndIf
			EndIf
		EndIf
	EndIf

	If *FilenameIntern <> #Null
		FreeMemory(*FilenameIntern)
		*FilenameIntern = #Null
	EndIf

	If *FilenameExtern <> #Null
		VirtualFreeEx_(ProcessHandle, *FilenameExtern, 0, #MEM_RELEASE)
		*FilenameExtern = #Null
	EndIf

	If ProcessHandle <> 0
		CloseHandle_(ProcessHandle)
		ProcessHandle = 0
	EndIf

	ProcedureReturn Result
EndProcedure

Process = RunProgram("TestEXE.exe", "", GetCurrentDirectory(), #PB_Program_Open)
If Process
	InjectLibary(ProgramID(Process),GetCurrentDirectory()+"TestDLL.dll")
EndIf
TestExe.exe:

Code: Select all

Delay(2000)

OpenWindow(0,0,0,500,500,"")
WebGadget(0,0,0,500,500,"http://www.purebasic.com") 

MessageRequester("Information",": (")
DarkDragon
Addict
Addict
Posts: 2124
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: intercept API

Post by DarkDragon »

Michael Vogel wrote:
DarkDragon wrote:Well I've done a hooking-code which works on Windows 7 x64 compiled with 64bit and 32bit. It is basic hooking and uses the disassembler of purebasic, which sometimes really works wrong. And you can't call the old method at the moment.

http://www.bradan.eu/files/hook.zip (Your antivirus will recognize it as a virus, sorry)
I had a working tool to debug network traffic for a network game written in purebasic (4.x), but meantime (windows 8.1 instead of xp, purebasic version 5+) it doesn't work anymore...
...so I try to find an alternative to write a log file showing the network data of the program. I tried to modify your code but I wasn't able to hook the winsock functions receive and send...
I haven't used windows and purebasic in a while now, but problems which could occur:

- the winsock libraries are not all loaded when you inject the hook
- the disassembler might still not be bugfree (I remember having problems with it)
- there is a jump/branch instruction right at the beginning of the functions which leads to really wrong behavior
- the functions use some anti-hook mechanisms (checking own memory or similar)
bye,
Daniel
Post Reply