AU3 Detour UDF - A simple way

07/25/2011 14:28 buFFy!#1
Here we go. Example is included
If you have any wishes concerning functions, just post here. same with questions!

Functions:


Code:
Global Const $PAGE_EXECUTE = 0x10
Global Const $PAGE_EXECUTE_READ = 0x20
Global Const $PAGE_EXECUTE_READWRITE = 0x40
Global Const $PAGE_EXECUTE_WRITECOPY = 0x80

Global Const $PAGE_NOACCESS = 0x1
Global Const $PAGE_READONLY = 0x2
Global Const $PAGE_READWRITE = 0x4
Global Const $PAGE_WRITECOPY = 0x8

Global Const $MEM_COMMIT = 0x1000
Global Const $MEM_RESERVE = 0x2000
Global Const $MEM_RESET = 0x80000
Global Const $MEM_DECOMMIT = 0x4000
Global Const $MEM_RELEASE = 0x8000

Global Const $PROCESS_ALL_ACCESS = 0x1F0FFF

Func OpenProcess($dwAccess, $bInheritHandle, $dwProcessId)
	$ret = DllCall('kernel32.dll', 'dword', 'OpenProcess', 'dword', $dwAccess, 'bool', $bInheritHandle, 'dword', $dwProcessId)
	Return $ret[0]
EndFunc   ;==>OpenProcess

Func CloseHandle($hObject)
	$ret = DllCall('kernel32.dll', 'bool', 'CloseHandle', 'handle', $hObject)
	Return $ret[0]
EndFunc   ;==>CloseHandle

Func ReadProcessMemory($hProcess, $lpBaseAddress, $Type = 'dword')
	$dsBuffer = DllStructCreate($Type);
	DllCall('kernel32.dll', 'bool', 'ReadProcessMemory', 'handle', $hProcess, 'ptr', $lpBaseAddress, 'ptr', DllStructGetPtr($dsBuffer), 'int', DllStructGetSize($dsBuffer), 'int', 0)
	Return DllStructGetData($dsBuffer, 1)
EndFunc   ;==>ReadProcessMemory

Func WriteProcessMemory($hProcess, $lpBaseAddress, $Value, $Type = 'dword')
	$dsBuffer = DllStructCreate($Type)
	DllStructSetData($dsBuffer, 1, $Value)
	DllCall('kernel32.dll', 'bool', 'WriteProcessMemory', 'handle', $hProcess, 'ptr', $lpBaseAddress, 'ptr', DllStructGetPtr($dsBuffer), 'int', DllStructGetSize($dsBuffer), 'int', 0)
EndFunc   ;==>WriteProcessMemory

Func VirtualAllocEx($hProcess, $lpAddress, $iSize, $dwAllocationType, $dwProtection)
	$ret = DllCall('kernel32.dll', 'int', 'VirtualAllocEx', 'handle', $hProcess, 'ptr', $lpAddress, 'int', $iSize, 'dword', $dwAllocationType, 'dword', $dwProtection)
	Return $ret[0]
EndFunc   ;==>VirtualAllocEx

Func VirtualFreeEx($hProcess, $lpAddress, $iSize, $dwFreeType)
	$ret = DllCall('kernel32.dll', 'bool', 'VirtualFreeEx', 'handle', $hProcess, 'ptr', $lpAddress, 'int', $iSize, 'dword', $dwFreeType)
	Return $ret[0]
EndFunc   ;==>VirtualFreeEx

Func VirtualProtectEx($hProcess, $lpAddress, $iSize, $dwNewProtection)
	$dsBuffer = DllStructCreate('dword')
	DllCall('kernel32.dll', 'bool', 'VirtualProtectEx', 'handle', $hProcess, 'ptr', $lpAddress, 'int', $iSize, 'dword', $dwNewProtection, 'dword', DllStructGetPtr($dsBuffer))
	Return DllStructGetData($dsBuffer, 1)
EndFunc   ;==>VirtualProtectEx

Func GetProcAddress($szFunctionname, $szDLL)
	$aRet = DllCall('kernel32.dll', 'handle', 'LoadLibrary', 'str', $szDLL)
	If $aRet[0] == 0 Then
		SetError(1)
		Return
	EndIf

	$pAdd = DllCall('kernel32.dll', 'ptr', 'GetProcAddress', 'handle', $aRet[0], 'str', $szFunctionname)
	If $pAdd[0] == 0 Then
		SetError(2)
		Return
	EndIf

	DllCall('kernel32.dll', 'bool', 'FreeLibrary', 'handle', $aRet[0])

	Return hex(number( $pAdd[0] ))
EndFunc   ;==>GetProcAddress

;credits to luzifer (not made by me, just edited to let it work with readprocessmemory)
Func FindPattern($ah_Handle, $pattern, $after = False, $iv_addrStart = 0x00400000, $iv_addrEnd = 0X00FFFFFF, $step = 51200)
	$pattern = StringRegExpReplace($pattern, "[^0123456789ABCDEFabcdef.]", "")
	If StringLen($pattern) = 0 Then
		SetError(2)
		Return -2
	EndIf
	For $addr = $iv_addrStart To $iv_addrEnd Step $step - (StringLen($pattern) / 2)
		StringRegExp(ReadProcessMemory($ah_Handle, $addr, "byte[" & $step & "]"), $pattern, 1, 2)
		If Not @error Then
			If $after Then
				Return StringFormat("0x%.8X", $addr + ((@extended - 2) / 2))
			Else
				Return StringFormat("0x%.8X", $addr + ((@extended - StringLen($pattern) - 2) / 2))
			EndIf
		EndIf
	Next
	Return -3
EndFunc   ;==>FindPattern

Func Detour($hProcess, $lpAddress, $szCode, $iLength = 5)
	If StringLen($szCode) == 0 Then
		SetError(1)
		Return
	EndIf
	Local $ret[2] = [$lpAddress, ""]

	$oCode = StringSplit($szCode, "/")

	$Alloc = VirtualAllocEx($hProcess, 0, $oCode[0] + 12, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
	If $Alloc == 0 Then
		SetError(2)
		Return
	EndIf

	For $i = 1 To $oCode[0] Step 1
		WriteProcessMemory($hProcess, $Alloc + $i - 1, $oCode[$i])
	Next

	$tAddr = $Alloc+$oCode[0]

	WriteProcessMemory($hProcess, $Alloc + $oCode[0], 0xE9)
	WriteProcessMemory($hProcess, $Alloc + $oCode[0] + 1, ($lpAddress-$tAddr))

	$flOldProtect = VirtualProtectEx($hProcess, $lpAddress, $iLength, $PAGE_EXECUTE_READWRITE)

	For $i = 0 To $iLength - 1 Step 1
		$ret[1] &= '0x' & Hex(ReadProcessMemory($hProcess, $lpAddress + $i, 'byte'), 2) & "/"
	Next

	WriteProcessMemory($hProcess, $lpAddress, 0xE9)
	WriteProcessMemory($hProcess, $lpAddress + 1, ($Alloc - $lpAddress) - $iLength, 'ptr')
	VirtualProtectEx($hProcess, $lpAddress, $iLength, $flOldProtect)

	For $i = 0 To $iLength - 6 Step 1
		WriteProcessMemory($hProcess, $lpAddress + 5 + $i, 0x90, 'byte')
	Next

	Return $ret

EndFunc   ;==>Detour

Func Retour($hProcess, $arDetour)
	If Not IsArray($arDetour) Then
		SetError(1)
		Return
	EndIf

	Local $oCode = StringSplit($arDetour[1], "/")
	Local $flOldProtect = VirtualProtectEx($hProcess, $arDetour[0], $oCode[0], $PAGE_EXECUTE_READWRITE)

	For $i = 1 To $oCode[0] Step 1
		WriteProcessMemory($hProcess, ($arDetour[0] + $i) - 1, $oCode[$i])
	Next

	VirtualProtectEx($hProcess, $arDetour[0], $oCode[0], $flOldProtect)
	VirtualFreeEx($hProcess, $arDetour[0], $oCode[0] + 12, $MEM_RELEASE)

	Return 1
EndFunc   ;==>Retour

Func MemSet($hProcess, $Address, $Value, $iSize)
	$flOldProtect = VirtualProtectEx($hProcess, $Address, $iSize, $PAGE_EXECUTE_READWRITE)
	For $i = 0 To $iSize Step 1
		WriteProcessMemory($hProcess, $Address + $i, $Value, 'byte')
	Next
	VirtualProtectEx($hProcess, $Address, $iSize, $flOldProtect)
	Return
EndFunc   ;==>MemSet

Func MemCpy($hProcess, $Dst, $Src, $iSize)
	If $iSize == 0 Then
		SetError(1)
		Return
	EndIf

	For $i = 0 To $iSize
		$tByte = ReadProcessMemory($hProcess, $Src + $i, 'byte')
		WriteProcessMemory($hProcess, $Dst + $i, $tByte, 'byte')
	Next

	Return
EndFunc   ;==>MemCpy

Func MemCmp($hProcess, $Reg1, $Reg2, $iSize)
	If $iSize == 0 Then
		SetError(1)
		Return
	EndIf

	Return StringCompare(ReadProcessMemory($hProcess, $Reg1, 'byte[' & $iSize & ']'), ReadProcessMemory($hProcess, $Reg2, 'byte[' & $iSize & ']'))
EndFunc   ;==>MemCmp
However, you will never be able to hook as comfortable as in C++.

greetz, coRe
07/25/2011 16:28 bollen#2
Ein bisschen Erklärung wäre nützlich was die einzelnen Funktionen können.
Wenn du dir schon die mühe machst.
07/25/2011 17:52 buFFy!#3
Die Funktionen sind mehr oder weniger portiert (teilweise leicht modifiziert).
Demnach 'bewirken' sie das gleiche, wie sonst auch. Trotzdem leg ich noch was bei.

Edit: im Spoiler

Vote 4 Sticky ! :rolleyes:
07/25/2011 21:20 kknb#4
hahaha u-coRe @au3 mode :)

nett gemacht!
07/26/2011 14:39 PenGuin :O#5
Nett gemacht, aber eher mit Kanonen auf Spatzen geschossen :D
Wer Detouren will, sollte auf C++ zurückgreifen.
07/26/2011 14:47 buFFy!#6
Quote:
Originally Posted by PenGuin :O View Post
Nett gemacht, aber eher mit Kanonen auf Spatzen geschossen :D
Wer Detouren will, sollte auf C++ zurückgreifen.
Meine Rede. Aber viele begreifen es einfach nicht und wollen unter allen Umständen unbedingt au3 nutzen ^^
07/26/2011 18:34 lolkop#7
würde empfehlen noch CreateRemoteThread hinzuzufügen, um so in der lage zu sein funktionen aus dem target direkt aufzurufen.

wäre in diesem falle natürlich auch angebracht die kernel32.dll erst zu laden, und am ende zu schließen, da dllcall dies sonst bei jedem aufruf macht.
07/26/2011 22:50 buFFy!#8
eigentlich unnötig, call tuts auch. createremotethread ist nur bei funktionen ohne parameter sinnvoll.
07/27/2011 10:51 lolkop#9
Quote:
Originally Posted by u-coRe View Post
eigentlich unnötig, call tuts auch. createremotethread ist nur bei funktionen ohne parameter sinnvoll.
calls bringen nur in codecaves etwas.

will man funktionen aus autoit heraus aufrufen (mit oder ohne parameter) macht man das über createremotethread.
07/27/2011 12:43 buFFy!#10
achso meinst du das. ja klar das macht sinn. ich dachte du willst das ich das createremotethread zum detour hinzufüge o0
07/28/2011 00:22 MrSm!th#11
Verstehe den Sinn nicht, um C++ oder Inline ASM kommt man doch eh nicht herum.
Und Code Injection via WriteProcessMemory + dann auch noch detouren...da macht eine direkte Dll Injection mehr Sinn und da muss man wenigstens nicht auf evtl. vom Anti Cheat kontrollierte APIs wie WriteProcessMemory zurückgreifen.

Oh und naja wirklich komfortabel ist die Detour Funktion nicht ;/
Ich würde da doch eher zu MS Detours greifen, da muss man keine Länge angeben und es wird wenigstens dafür gesorgt, dass nicht mitten beim Schreiben die Funktion aufgerufen wird.

Alles in allem eine nette Spielerei für die Leute, die mit Autoit immer auf der selben Stufe wie C++ sein wollen, aber eigentlich unnötig.
07/28/2011 10:37 buFFy!#12
sicher gehts mit c++ viel leichter. das hier ist nur ne demo das das mit au3 auch geht ;>
07/28/2011 17:20 MrSm!th#13
Wenn man sich schon die Arbeit machen muss, ASM Code in Form von fertig assemblierten Opcodes per WriteProcessMemory in den Prozess zu schreiben, kann man auch gleich den Jump selbst platzieren, da nimmt einem diese Funktion auch nicht mehr viel ab.
07/28/2011 20:30 buFFy!#14
dann zeig mir mal wie du den jump, dynamisch natürlich, selbst platzierst. klar ist das ganze aufwändig, jedoch nicht ganz ineffektiv, denn auch mit au3 kannst du nach mustern im speicher suchen.

btw brauche ich, um nen fertigen hook mit au3 zumachen (mit dieser udf) keine 10 minuten. kommt eben immer drauf an wie man sich anstellt.

desweiteren kann ich nur immer wieder wiederholen das das ganze nur ne demo für die ist, die unbedingt au3 für sowas hernehmen wollen.
07/28/2011 22:05 MrSm!th#15
Dann ist deine Hook Funktion aber sicher nicht gerade sehr aufwendig.