Что нового

"THREADSTACK0" модуль, как базовый адрес

Sαuron

Новичок
Сообщения
45
Репутация
1
Решил запилить чит для любимой игры, вычислил с помощью CE 6.5 цепочку смещений до нужного адреса, которая за пол года фиксов/патчей, до сих пор ведет к нужному адресу и надо сказать - она единственная.
Выглядит нестандартно, не вида [xxx.exe - 0x00000B34], а [xxx - 0x00000B34], то есть это модуль, но не сам процесс, вот скрин этих сещений в CE:

Сама игра имеет процесс с именем game.exe
Проблема в том, что функция MemoryModuleGetBaseAddress(), которую я нашел на этом же форуме, находит базовые адреса только процессов .ЕХЕ, а этот модуль "THREADSTACK0" она не переваривает, возвращает 0.
Вот весь код, включая функцию.
Код:
#include <NomadMemory.au3>

$game_name_proc = 'game.exe'
$game_pid 		= processexists($game_name_proc)
;~ _memoryopen($game_pid)


$a = MemoryModuleGetBaseAddress($game_pid, "THREADSTACK0")
msgbox('', '', $a)



;==========================================================================================
;GetBaseAddress func
;==========================================================================================
Func  MemoryModuleGetBaseAddress($iPID , $sModule)
    If  Not  ProcessExists ($iPID) Then  Return  SetError (1 , 0 , 0)

    If  Not  IsString ($sModule) Then  Return  SetError (2 , 0 , 0)

    Local    $PSAPI=DllOpen ("psapi.dll")

    ;Get Process Handle
    Local    $hProcess
    Local    $PERMISSION=BitOR (0x0002, 0x0400, 0x0008, 0x0010, 0x0020) ; CREATE_THREAD, QUERY_INFORMATION, VM_OPERATION, VM_READ, VM_WRITE

    If  $iPID>0 Then
        Local  $hProcess=DllCall ("kernel32.dll" , "ptr" , "OpenProcess" , "dword" , $PERMISSION , "int" , 0 , "dword" , $iPID)
        If  $hProcess [ 0 ] Then
            $hProcess=$hProcess [ 0 ]
        EndIf
    EndIf

    ;EnumProcessModules
    Local    $Modules=DllStructCreate ("ptr[1024]")
    Local    $aCall=DllCall ($PSAPI , "int" , "EnumProcessModules" , "ptr" , $hProcess , "ptr" , DllStructGetPtr ($Modules), "dword" , DllStructGetSize ($Modules), "dword*" , 0)
    If  $aCall [ 4 ]>0 Then
        Local    $iModnum=$aCall [ 4 ] / 4
        Local    $aTemp
        For  $i=1 To  $iModnum
            $aTemp= DllCall ($PSAPI , "dword" , "GetModuleBaseNameW" , "ptr" , $hProcess , "ptr" , Ptr(DllStructGetData ($Modules , 1 , $i)) , "wstr" , "" , "dword" , 260)
            If  $aTemp [ 3 ]=$sModule Then
                DllClose ($PSAPI)
                Return  Ptr(DllStructGetData ($Modules , 1 , $i))
            EndIf
        Next
    EndIf

    DllClose ($PSAPI)
    Return  SetError (-1 , 0 , 0)

EndFunc

Как же вычислить базовый адрес этого модуля?
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
Потому что это база не модуля, а стэка. Приостанавливаете поток, получаете его контекст и работаете с полученным из контекста адресом стэка.
 
Автор
S

Sαuron

Новичок
Сообщения
45
Репутация
1
firex сказал(а):
Потому что это база не модуля, а стэка. Приостанавливаете поток, получаете его контекст и работаете с полученным из контекста адресом стэка.
Это же сколько велосипедов придется изобрести (((( А можно ли сделать это проще? Хоть как-то? Очень не хочется вызывать тонну низкоуровневых функций, которые не пойми как будут работать на компьютерах друзей. Можно ли функцией _WinAPI_GetModuleInformation получить базовый адрес модуля?


Добавлено:
Сообщение автоматически объединено:

Ладно, если проще нельзя... Пока вот что собрал (заморозка/разморозка работает), но на стадии получения контекста, нужно передать hThread это типа Handle нужного потока, где его взять???
Вот код на данный момент:
Код:
$pid = ProcessExists('game.exe')
$pHandle = DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', 0x1f0fff, 'int', False, 'int', $pid)

; Приостановить процесс
;========================================================================
DllCall("ntdll.dll","int","NtResumeProcess","int",$pHandle[0])

; Создание структуры CONTEXT 
;========================================================================
Global Const $SIZE_OF_80376_REGISTERS = 80

Global Const $tFLOATING_SAVE_AREA = "DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE RegisterArea[" & $SIZE_OF_80376_REGISTERS & "]; DWORD Cr0NpxState"
Global Const $sFLOATING_SAVE_AREA = DllStructCreate($tFLOATING_SAVE_AREA)
Global Const $pFLOATING_SAVE_AREA = DllStructGetPtr($sFLOATING_SAVE_AREA)

Global Const $MAXIMUM_SUPPORTED_EXTENSION = 512

Global Const $tCONTEXT = "DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; FLOATING_SAVE_AREA " & $pFLOATING_SAVE_AREA & "; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[" & $MAXIMUM_SUPPORTED_EXTENSION & ']'
Global Const $sCONTEXT = DllStructCreate($tCONTEXT)
Global Const $pCONTEXT = DllStructGetPtr($sCONTEXT)

; Получение контекста
;========================================================================
DllCall('kernel32.dll', "BOOL", "GetThreadContext", "hwnd", $hThread, "ptr", $pCONTEXT)

; Возобновить процесс
;========================================================================
DllCall("ntdll.dll","int","NtSuspendProcess","int",$pHandle[0])
DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $pHandle)
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
Sαuron
Вы все не так поняли и не так сделали. Для вашего случая документированного метода нет, поэтому нужно выкручиваться: раскрутить стек по его вершине (регистр esp из контекста) или воспользоваться недокументированной структурой _TEB.

Код:
#include <ProcessConstants.au3>
#include <WinAPIProc.au3>
#include <WinAPISys.au3>


Global Const $THREAD_ALL_ACCESS = 0x1F03FF

Global Const $tagTHREAD_BASIC_INFORMATION = "dword ExitStatus; ptr TebBaseAddress; handle CLIENT_ID[2]; ulong_ptr Reserved[3];"
Global Const $tagNT_TIB = "ptr ExceptionList; ptr StackBase; ptr StackLimit; ptr SubSystemTib; ulong_ptr u1; ptr ArbitraryUserPointer; ptr Self;"


Local $hProcess, $aThreads, $hThread, $aRes, $iBytes, _
	$iPID = ProcessExists("opera.exe"), _
	$tTBI = DllStructCreate($tagTHREAD_BASIC_INFORMATION), _
	$tNT_TIB = DllStructCreate($tagNT_TIB)
; ---
$hProcess = _WInAPI_OpenProcess($PROCESS_ALL_ACCESS, False, $iPID)
If Not $hProcess Then _
	Exit

$aThreads = _WinAPI_EnumProcessThreads($iPID)
If Not @Error Then
	For $i = 0 To $aThreads[0]
		$hThread = _WinAPI_OpenThread($THREAD_ALL_ACCESS, False, $aThreads[$i])
		If Not $hThread Then _
			ContinueLoop

		$aRes = DllCall("ntdll.dll", "dword", "NtQueryInformationThread", _
			"handle", $hThread, _
			"dword", 0, _
			"ptr", DllStructGetPtr($tTBI), _
			"ulong", DllStructGetSize($tTBI), _
            "dword*", 0 _
			)
		If Not @Error And Not $aRes[0] Then
			If _WinAPI_ReadProcessMemory($hProcess, $tTBI.TebBaseAddress, DllStructGetPtr($tNT_TIB), DllStructGetSize($tNT_TIB), $iBytes) Then
				ConsoleWrite("Stack base of " & $aThreads[$i] & " thread is " & $tNT_TIB.StackBase & @CRLF)
			EndIf
		EndIf

		_WinAPI_CloseHandle($hThread)
	Next
EndIf

_WinAPI_CloseHandle($hProcess)


Func _WinAPI_OpenThread($iAccess, $bInherit, $iThreadID)
	Local $aResult = DllCall("kernel32.dll", "handle", "OpenThread", "dword", $iAccess, "bool", $bInherit, "dword", $iThreadID)
	If @error Then Return SetError(@error, @extended, 0)
	Return $aResult[0]
EndFunc
 
Автор
S

Sαuron

Новичок
Сообщения
45
Репутация
1
firex сказал(а):
Sαuron
Вы все не так поняли и не так сделали. Для вашего случая документированного метода нет, поэтому нужно выкручиваться: раскрутить стек по его вершине (регистр esp из контекста) или воспользоваться недокументированной структурой _TEB.

Спасибо, код действительно находит потоки и выводит их БА, среди них своего threadstack'a я не нашел, но заметил, что он всегда ниже 1го основного потока совсем чуть-чуть, адрес первого потока 0x00A40000, threadstack имел [0x00A40000-0x1E0], перезапускал многократно клиент, сейчас первый поток 0x00A90000, threadstack [0x00A90000-0x6D0], всегда так, стэк смещен ниже от потока и всегда содержит значение "2005658988", сделал сканирование от 1го потока вниз, пока не попадется адрес с этим значением, я так понял, самый максимум его смещения вниз это .StackLimit :smile:
 

gnomka

Новичок
Сообщения
2
Репутация
0
Спасибо, код действительно находит потоки и выводит их БА, среди них своего threadstack'a я не нашел, но заметил, что он всегда ниже 1го основного потока совсем чуть-чуть, адрес первого потока 0x00A40000, threadstack имел [0x00A40000-0x1E0], перезапускал многократно клиент, сейчас первый поток 0x00A90000, threadstack [0x00A90000-0x6D0], всегда так, стэк смещен ниже от потока и всегда содержит значение "2005658988", сделал сканирование от 1го потока вниз, пока не попадется адрес с этим значением, я так понял, самый максимум его смещения вниз это .StackLimit :smile:
Я убил месяц на поиск базового адреса threadstack0 средствами автоит или питон или c++ не чего не работало и даже форки и недокументированые функции даже git hub не помог , в итоге что я сделал, просто создал трейнер на луа скрипте cheat engine который : ищет в памяти по указателю с базой threadstack0 + смещениями то что мне надо например координаты персонажа, и каждые 250 миле секунд делаю перезапись в файл pos. txt найденного значения, чтоб найти адреса и написать луа скрипт для трейнера ушло всего минут 10 теперь мой скрипт бота на автоите просто читает с файла значения и не надо не чего придумывать
 
Верх