12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
三国霸业 战车-珍宝-觉醒-攻城掠地SF-全新玩法 免费玩新区 攻城掠地私服 进入游戏
手游私服盒子 各类免费游戏 0.1折送海量资源 各类手游私服 进入游戏
皇家MU2 《奇迹 2:传奇》韩国网禅公司《奇迹》正统续作。 3D锁视角Mmrpg 暗黑3+传奇+流放之路+奇迹 进入游戏
查看: 308|回复: 0

Python64位游戏读写--GTA锁血

[复制链接]

49

主题

49

帖子

108

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
108
发表于 2020-6-30 22:45:13 | 显示全部楼层 |阅读模式

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


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

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

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

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

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

由于游戏很大,所以第一次搜增加的时候,会很卡,而且会扫很久,我的电脑要扫大概两分半钟,而且内存会被吃满

而且扫的次数多了,会产生很多临时文件

像我这样,C盘直接没位置了,所以建议备一个清理C盘的软件。时不时清理临时文件
看会小说或者刷会短视频,等扫描结果出来以后,就再次输入作弊代码,就可以将无敌关闭(我一开始不知道,傻傻得等了五分钟)。
如何查看是否关闭,看右下角的倒计时是否存在。如果没了,那就是关闭了。
这时候搜索减少的数值。

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



快捷键,CTRL+D,可以快速查看该地址反汇编地址。
因为我搜索过很多次,所以认得特征,当反汇编窗口的代码,是以下这串时候,我就知道找到了
or [rax],al
为什么了,因为这个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 函数

ZwWow64QueryInformationProcess64
ZwWow64ReadVirtualMemory64
ZwWow64WriteVirtualMemory64
ZwWow64CallFunction64

32位程序几乎可以获取64位程序的全部函数调用功能。
首先导入函数

基本操作都没啥不同的。
# -*- coding:utf-8 -*-"""@author: @file: GTA.py@time: 2020-06-21 13:49@desc: KeyboArd"""import win32process#进程模块import win32api#主要用来注册热键import ctypes#C语言类型from win32gui import FindWindow#界面from ctypes import c_long , c_int , c_void_p, windll, WinDLL, c_ulonglong, byref初始化

ntdll = WinDLL("ntdll.dll")#调用ntdll库kernel32 = ctypes.windll.LoadLibrary("kernel32.dll")#调用kernel32库GetLastError = kernel32.GetLastError#调用GetLastError函数GTA = 0x7FF79B5D0000#GTA.EXE的基址,原本是打算通过模块名字获取的,但是不知道为什么返回-1.可能是64位游戏,涉及到一些权限问题,后面在研究一下,目前主要是为了达到目的。STANDARD_RIGHTS_REQUIRED = 0x000F0000#这两个的值,是在C++那里获取过来的。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),  # 接收进程ID                ('InheritedFromUniqueProcessId', ctypes.c_ulonglong)]  # 接收父进程ID## OpenProcessOpenProcess = windll.kernel32.OpenProcessOpenProcess.argtypes = [c_void_p, c_int, c_long]OpenProcess.rettype = c_long## CloseHandleCloseHandle = windll.kernel32.CloseHandleCloseHandle.argtypes = [c_void_p]CloseHandle.rettype = c_intdef _GetProcessId(className,windowName):    hGameWindow = FindWindow(className, windowName)    pid = win32process.GetWindowThreadProcessId(hGameWindow)[1]    return piddef _GetPorcessHandle(pid):    hGameHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)    return hGameHandleProcessId = _GetProcessId("grcWindow", u"Gra***** A****V")_hGameHandle = _GetPorcessHandle(ProcessId)

对64位内存读操作

def _ReadMemeryLong64(addr, bufflength):    addr = c_ulonglong(addr)#64位游戏,我测试过,如果只写c_ulong() 会报错,说有冲突。    ret = c_ulonglong()#所以这里也都保持同样的长度把    BufferLength = c_ulonglong(bufflength)    ntdll.ZwWow64ReadVirtualMemory64(int(_hGameHandle), addr, byref(ret), BufferLength, 0)#ZwWow64ReadVirtualMemory64和ReadProcessInt 这个函数操作类似。    return ret.value64位通过模块名获取基址

def GetBaseAddr(ModuleName):  #这是论坛里一位大佬写的,为了方便快捷,先复制粘贴过来,这代码我也没看懂,好像涉及到了pe知识,后面自己在 写一个。    # 传入需要查找的模块的名称,就可以返回相应的模块基址了    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):  # 这里用for循环其实是怕程序卡死,下面如果出了问题不能退出的话,循环结束一样可以退出        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):    #"GTA5.exe"+02D06110 +28+298+c8+a8+188  这是找到的基址    value = GTA+ 0x02D06110#GTA的基址等于0x7FF79B5D0000 ,如果重启了电脑,这个基址会变,所以一定要写64位通过模块名读取基址。    value1 = _ReadMemeryLong64(value,8)#先读取一下"GTA5.exe"+02D06110的基址。看下是否正确。    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)    # #value1 = value++0x28+0x298+0xc8+0xa8+0x188    print("0x%08X"%value2)    print(value)    return value5value:"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位写操作

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)##写法也跟WriteProcessMemory这个函数相似无敌

初始:4194316
无敌:4194572
def set_invincible(hGameHandle,address):    while True:        WriteMemeryLong64(hGameHandle,address+0x188,4194572,4)#开启无敌        if(win32api.GetAsyncKeyState(35)!=0):#当按下END键,就关闭无敌,将值写回正常            WriteMemeryLong64(hGameHandle, address + 0x188, 4194316, 4)#关闭无敌            CloseHandle(hGameHandle)#关闭句柄            exit(0)#退出程序开启:

关闭:

完整代码

# -*- coding:utf-8 -*-"""@author: @file: GTA.py@time: 2020-06-21 13:49@desc: KeyboArd"""import win32process#进程模块import win32api#主要用来注册热键import ctypes#C语言类型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_pntdll = WinDLL("ntdll.dll")kernel32 = ctypes.windll.LoadLibrary("kernel32.dll")GetLastError = kernel32.GetLastError#GTA = 0x7FF79B5D0000STANDARD_RIGHTS_REQUIRED = 0x000F0000SYNCHRONIZE = 0x00100000PROCESS_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),  # 接收进程ID                ('InheritedFromUniqueProcessId', ctypes.c_ulonglong)]  # 接收父进程ID## OpenProcessOpenProcess = windll.kernel32.OpenProcessOpenProcess.argtypes = [c_void_p, c_int, c_long]OpenProcess.rettype = c_long## CloseHandleCloseHandle = windll.kernel32.CloseHandleCloseHandle.argtypes = [c_void_p]CloseHandle.rettype = c_intdef _GetProcessId(className,windowName):    hGameWindow = FindWindow(className, windowName)    pid = win32process.GetWindowThreadProcessId(hGameWindow)[1]    return piddef _GetPorcessHandle(pid):    hGameHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)    return hGameHandleProcessId = _GetProcessId("grcWindow", u"G*********o 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.valuedef 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):#这个函数用以读取模块名称,与ReadVirtualMemory64不同的点还有一个是我们会传入一个缓冲区的长度length,用于定义一个c_wchar_p的缓冲区    addr = c_ulonglong(addr)    ret = c_wchar_p("0" * length)#这里选用wchar其实与编码有关,感兴趣的同学自行百度wchar,宽字符等关键字学习    BufferLength = c_ulonglong(n)    ntdll.NtWow64ReadVirtualMemory64(int(_hGameHandle), addr, ret, BufferLength, 0)    return ret.valuedef 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):  # 这里用for循环其实是怕程序卡死,下面如果出了问题不能退出的话,循环结束一样可以退出        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):    #"GTA5.exe"+02D06110 +28+298+c8+a8+188    value = GTA+ 0x02D06110    value1 = _ReadMemeryLong64(value,8)#先读取一下"GTA5.exe"+02D06110的基址。看下是否正确。    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)    #value1 = value++0x28+0x298+0xc8+0xa8+0x188   # print("0x%08X"%value6)    print(value6)    return value5def 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("****5.exe")    invincible = get_invincible(_hGameHandle, moudle)    #print("0x%08X" % moudle)    #print(moudle)    #print("0x%08X" % modulename)    set_invincible(_hGameHandle,invincible)    CloseHandle(_hGameHandle)if __name__ == '__main__':    main()



来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-11-25 11:29 , Processed in 0.093750 second(s), 32 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表