
EPIC送了GTA5,最近考完试和朋友一起玩了下,由于刚开始,等级低,朋友带我打任务的时候,完全就打不过,我的甲没几下就爆了,刚开始没什么。
但是今天去打末日3的时候,由于只有两个人,玩过的都知道,末日3是需要一个人去玩小游戏,然后其他人保护玩小游戏那个队友,末日3的NPC是会一直刷,怎么打都打不完,有一瞬间就变成了CSGO练爆头模式,完全没得打(打不过就充钱,没得充钱就变强)。后面搜了搜,发现别人歪瓜的截图,有锁血功能,就想去了解一下。
打开GTAV,进入故事模式。GTAV官方在故事模式中,有给出作弊代码,其中有一个无敌五分钟的命令。从这个命令入手,查找他的基址,没准能用。
作弊代码:PAINKILLER
1 2 3 4 5 6 7 8 9
| 搜索思路 👇 开启无敌时候,可能会有数值增加,可能有一个数值或者开关,会变为1。这时搜索增加的数值 关闭无敌时候,可能会有数值减少,可能有一个数值或者开关,会变为0。这时搜索减少的数值
开启无敌时候,可能会有数值减少,可能有一个数值或者开关,某个数值减少。这时搜索减少的数值 关闭无敌时候,可能会有数值减少,可能有一个数值或者开关,某个数值增加。这时搜索增加的数值 👆
|
搜索基址

CE加载GTA5,先通过常规思路,无敌搜增加,关闭搜减少。

即使这游戏是64位的,但是依然扫4字节就够了。首先先扫一次未知的初始值。

进入GTA,按~
键,输入作弊代码PAINKILLER

输入成功时候,右下角会有无敌时间,正常为五分钟。

这时候去CE搜索增加的数值

由于游戏很大,所以第一次搜增加的时候,会很卡,而且会扫很久,我的电脑要扫大概两分半钟,而且内存会被吃满
而且扫的次数多了,会产生很多临时文件
像我这样,C盘直接没位置了,所以建议备一个清理C盘的软件。时不时清理临时文件
看会小说或者刷会短视频,等扫描结果出来以后,就再次输入作弊代码,就可以将无敌关闭(我一开始不知道,傻傻得等了五分钟)。

如何查看是否关闭,看右下角的倒计时是否存在。如果没了,那就是关闭了。
这时候搜索减少的数值。

步骤循环,等结果少于5000的时候。就可以通过搜索未变动的数值,来开始查找最终的基址。



快捷键,CTRL+D
,可以快速查看该地址反汇编地址。
因为我搜索过很多次,所以认得特征,当反汇编窗口的代码,是以下这串时候,我就知道找到了

为什么了,因为这个al在线上模式时候,他是0或者1,0就是关闭无敌,1就是开启无敌。
一开始我怎么找到这个的了,我当时扫了很多次,发现有一次,他的值不是al,而是0,然后当我开启无敌时候,他就变为1了。我就把它认住了。发现有的时候在线下模式,他就是会这样,抽风。
关闭无敌的默认初始值是:4194316
当你把他的数值改为这个初始值时,他这个al
就会变为0

但是即使你把它改了,他还是会变,有时候会变为12
,有时候会变很大的数,但是你测试一下,将00
改为01
时候,在去做一些扣血的行为时候,是不会扣血的,达到了无敌的效果。
基址找到了,那就开始找他的静态基址。
一开始尝试过一步一步找,然后发现,扫出来的基址过多,比较麻烦,所以后面决定使用指针搜索

我这里没调参数,直接确定了。

最后扫出来的结果,有9419539
个,观察他的值,值等于初始值4194316
或等于基址目前的值的时候,就把它双击,添加到地址表中。


一定要选多几个,因为进入线上模式时候,值会变,有的会变成?
号,有的是不知道啥值,所以要选多几个加以观察,或者不关闭指针扫描结果窗口。

最终我找出来的基址
"GTA5.exe"+02D06110 +28+298+c8+a8+188
五层偏移。

代码编写

游戏是64位的,所以要用64位的函数。
WOW64 函数
1 2 3 4 5
| ZwWow64QueryInformationProcess64 ZwWow64ReadVirtualMemory64 ZwWow64WriteVirtualMemory64 ZwWow64CallFunction64 32位程序几乎可以获取64位程序的全部函数调用功能。
|
首先导入函数
基本操作都没啥不同的。
1 2 3 4 5 6 7 8 9 10 11 12
| """ @author: @file: GTA.py @time: 2020-06-21 13:49 @desc: KeyboArd """ import win32process import win32api import ctypes from win32gui import FindWindow from ctypes import c_long , c_int , c_void_p, windll, WinDLL, c_ulonglong, byref
|
初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| ntdll = WinDLL("ntdll.dll") kernel32 = ctypes.windll.LoadLibrary("kernel32.dll") GetLastError = kernel32.GetLastError GTA = 0x7FF79B5D0000 STANDARD_RIGHTS_REQUIRED = 0x000F0000 SYNCHRONIZE = 0x00100000 PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF)
class PROCESS_BASIC_INFORMATION(ctypes.Structure): _fields_ = [('ExitStatus', ctypes.c_ulonglong), ('PebBaseAddress', ctypes.c_ulonglong), ('AffinityMask', ctypes.c_ulonglong), ('BasePriority', ctypes.c_ulonglong), ('UniqueProcessId', ctypes.c_ulonglong), ('InheritedFromUniqueProcessId', ctypes.c_ulonglong)]
OpenProcess = windll.kernel32.OpenProcess OpenProcess.argtypes = [c_void_p, c_int, c_long] OpenProcess.rettype = c_long
CloseHandle = windll.kernel32.CloseHandle CloseHandle.argtypes = [c_void_p] CloseHandle.rettype = c_int
def _GetProcessId(className,windowName): hGameWindow = FindWindow(className, windowName) pid = win32process.GetWindowThreadProcessId(hGameWindow)[1] return pid
def _GetPorcessHandle(pid): hGameHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid) return hGameHandle
ProcessId = _GetProcessId("grcWindow", u"Grand Theft Auto V") _hGameHandle = _GetPorcessHandle(ProcessId)
|


对64位内存读操作
1 2 3 4 5 6
| def _ReadMemeryLong64(addr, bufflength): addr = c_ulonglong(addr) ret = c_ulonglong() BufferLength = c_ulonglong(bufflength) ntdll.ZwWow64ReadVirtualMemory64(int(_hGameHandle), addr, byref(ret), BufferLength, 0) return ret.value
|
64位通过模块名获取基址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| def GetBaseAddr(ModuleName): NumberOfBytesRead = c_ulong() Buffer = PROCESS_BASIC_INFORMATION() Size = c_ulong(48) name_len = len(ModuleName)
ntdll.NtWow64QueryInformationProcess64(int(_hGameHandle), 0, byref(Buffer), Size, byref(NumberOfBytesRead)) """ 这同样是一个未公开的api,可以通过他获取进程的信息,然后存入我们一开始定义的结构体中,他的五个参数分别是: 进程句柄,信息类型,缓冲指针,以字节为单位的缓冲大小, 写入缓冲的字节数 而至于下面为什么要这么写,其实涉及到了程序的PE结构,这里不做赘述,因为这个东西不是一会会说的清楚的,可以自行百度 """ ret = _ReadMemeryLong64(Buffer.PebBaseAddress + 24, 8) ret = _ReadMemeryLong64(ret + 24, 8)
for i in range(100000): modulehandle = _ReadMemeryLong64(ret + 48, 8) if modulehandle == 0: break nameaddr = _ReadMemeryLong64(ret + 96, 8) name = ReadProcessMemory64_Wchar(nameaddr, name_len * 2 + 1, name_len) if name == ModuleName: return modulehandle ret = _ReadMemeryLong64(ret + 8, 8)
|
对找到的基址进行读取
1 2 3 4 5 6 7 8 9 10 11 12 13
| def get_invincible(hGameHandle): value = GTA+ 0x02D06110 value1 = _ReadMemeryLong64(value,8) value2 = _ReadMemeryLong64(value1+0x28,8) value3 = _ReadMemeryLong64(value2+0x298,8) value4 = _ReadMemeryLong64(value3+0xc8,8) value5 = _ReadMemeryLong64(value4+0xa8,8) value6 = _ReadMemeryLong64(value5+0x188,8) print("0x%08X"%value2) print(value) return value5
|
value:"GTA5.exe"+02D06110

value1:GTA5.exe"+02D06110

value2:GTA5.exe"+02D06110+0x28

value3:GTA5.exe"+02D06110+0x28+0x298

value4:GTA5.exe"+02D06110+0x28+0x298+0XC8

value5:GTA5.exe"+02D06110+0x28+0x298+0XC8+0xa8

value6:GTA5.exe"+02D06110+0x28+0x298+0XC8+0xa8+0x188

成功读取到该值,为什么这么写,因为一开始我直接省略麻烦,写一堆,发现读的都是什么东西,太乱了。这样子容易找到问题。
64位写操作
1 2 3 4 5
| def WriteMemeryLong64(addr, bufflength, n): addr = c_ulonglong(addr) ret = c_ulonglong(bufflength) BufferLength = c_ulonglong(n) ntdll.ZwWow64WriteVirtualMemory64(int(_hGameHandle), addr, byref(ret), BufferLength, 0)
|
无敌
初始:4194316
无敌:4194572
1 2 3 4 5 6 7 8
| def set_invincible(hGameHandle,address): while True: WriteMemeryLong64(hGameHandle,address+0x188,4194572,4) if(win32api.GetAsyncKeyState(35)!=0): WriteMemeryLong64(hGameHandle, address + 0x188, 4194316, 4) CloseHandle(hGameHandle) exit(0)
|
开启:

关闭:

完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
| """ @author: @file: GTA.py @time: 2020-06-21 13:49 @desc: KeyboArd """ import win32process import win32api import ctypes from win32gui import FindWindow from ctypes import c_long , c_int , c_void_p, windll, WinDLL, c_ulonglong, byref,Structure,c_char,POINTER,sizeof,pointer,c_ulong,c_wchar_p
ntdll = WinDLL("ntdll.dll") kernel32 = ctypes.windll.LoadLibrary("kernel32.dll") GetLastError = kernel32.GetLastError
STANDARD_RIGHTS_REQUIRED = 0x000F0000 SYNCHRONIZE = 0x00100000 PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF)
class PROCESS_BASIC_INFORMATION(ctypes.Structure): _fields_ = [('ExitStatus', ctypes.c_ulonglong), ('PebBaseAddress', ctypes.c_ulonglong), ('AffinityMask', ctypes.c_ulonglong), ('BasePriority', ctypes.c_ulonglong), ('UniqueProcessId', ctypes.c_ulonglong), ('InheritedFromUniqueProcessId', ctypes.c_ulonglong)]
OpenProcess = windll.kernel32.OpenProcess OpenProcess.argtypes = [c_void_p, c_int, c_long] OpenProcess.rettype = c_long
CloseHandle = windll.kernel32.CloseHandle CloseHandle.argtypes = [c_void_p] CloseHandle.rettype = c_int
def _GetProcessId(className,windowName): hGameWindow = FindWindow(className, windowName) pid = win32process.GetWindowThreadProcessId(hGameWindow)[1] return pid
def _GetPorcessHandle(pid): hGameHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid) return hGameHandle
ProcessId = _GetProcessId("grcWindow", u"Grand Theft Auto V") _hGameHandle = _GetPorcessHandle(ProcessId)
def _ReadMemeryLong64(addr, bufflength): addr = c_ulonglong(addr) ret = c_ulonglong() BufferLength = c_ulonglong(bufflength) ntdll.ZwWow64ReadVirtualMemory64(int(_hGameHandle), addr, byref(ret), BufferLength, 0) return ret.value
def WriteMemeryLong64(addr, bufflength, n): addr = c_ulonglong(addr) ret = c_ulonglong(bufflength) BufferLength = c_ulonglong(n) ntdll.ZwWow64WriteVirtualMemory64(int(_hGameHandle), addr, byref(ret), BufferLength, 0)
def ReadProcessMemory64_Wchar(addr, n,length): addr = c_ulonglong(addr) ret = c_wchar_p("0" * length) BufferLength = c_ulonglong(n) ntdll.NtWow64ReadVirtualMemory64(int(_hGameHandle), addr, ret, BufferLength, 0) return ret.value
def GetBaseAddr(ModuleName): NumberOfBytesRead = c_ulong() Buffer = PROCESS_BASIC_INFORMATION() Size = c_ulong(48) name_len = len(ModuleName)
ntdll.NtWow64QueryInformationProcess64(int(_hGameHandle), 0, byref(Buffer), Size, byref(NumberOfBytesRead)) """ 这同样是一个未公开的api,可以通过他获取进程的信息,然后存入我们一开始定义的结构体中,他的五个参数分别是: 进程句柄,信息类型,缓冲指针,以字节为单位的缓冲大小, 写入缓冲的字节数 而至于下面为什么要这么写,其实涉及到了程序的PE结构,这里不做赘述,因为这个东西不是一会会说的清楚的,可以自行百度 """ ret = _ReadMemeryLong64(Buffer.PebBaseAddress + 24, 8) ret = _ReadMemeryLong64(ret + 24, 8)
for i in range(100000): modulehandle = _ReadMemeryLong64(ret + 48, 8) if modulehandle == 0: break nameaddr = _ReadMemeryLong64(ret + 96, 8) name = ReadProcessMemory64_Wchar(nameaddr, name_len * 2 + 1, name_len) if name == ModuleName: return modulehandle ret = _ReadMemeryLong64(ret + 8, 8)
def get_invincible(hGameHandle,GTA): value = GTA+ 0x02D06110 value1 = _ReadMemeryLong64(value,8) value2 = _ReadMemeryLong64(value1+0x28,8) value3 = _ReadMemeryLong64(value2+0x298,8) value4 = _ReadMemeryLong64(value3+0xc8,8) value5 = _ReadMemeryLong64(value4+0xa8,8) value6 = _ReadMemeryLong64(value5+0x188,8) print(value6) return value5
def set_invincible(hGameHandle,address): while True: WriteMemeryLong64(address+0x188,4194572,4)
if(win32api.GetAsyncKeyState(35)!=0): WriteMemeryLong64(address + 0x188, 4194316, 4) CloseHandle(hGameHandle) exit(0)
def main(): moudle = GetBaseAddr("GTA5.exe") invincible = get_invincible(_hGameHandle, moudle) set_invincible(_hGameHandle,invincible)
CloseHandle(_hGameHandle)
if __name__ == '__main__': main()
|


