因为昨天研究FPS游戏时候,发现有个动态地址每次重启电脑都会不同,然后因为有过用C和易语言编写指定模块名获取基址的经验,所以打算用Python来试试
在网上搜索了一点资料,发现有吾爱有一篇是使用Python32位,通过Ntdll
库进行模块遍历。
将代码复制粘贴,因为我使用的是Python64位的,改了改代码,但是发现失败了,搜不出来,因为代码涉及到PE头,目前还没碰到这块区域,代码作者也说他只是复制粘贴的,所以也不甚清楚为什么,就只能另寻出路了。
1 | def _ReadMemeryInt(hGameHandle,_address,bufflength): |
返回值是0,我也有尝试过修改 ret + xx
后面的数字进行搜索,原作者说这个数是涉及PE头的知识,后面发现,无论怎么改都搜不出来,就放弃了。
使用WinAPI完成指定模块基址读写
1.先了解下要使用到的函数
MODULEENTRY32
MODULEENTRY32是一种编程数据结构。
结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Describes an entry from a list of the modules belonging to the specified process.
typedef struct tagMODULEENTRY32 {
DWORD dwSize; //指定结构的长度,以字节为单位。在调用Module32First功能,设置这个成员SIZEOF(MODULEENTRY32)。如果你不初始化的dwSize,Module32First将失败。
DWORD th32ModuleID;//此成员已经不再被使用,通常被设置为1
DWORD th32ProcessID;//正在检查的进程标识符。这个成员的内容,可以使用Win32 API的元素
DWORD GlblcntUsage;//全局模块的使用计数,即模块的总载入次数。通常这一项是没有意义的,被设置为0xFFFF。
DWORD ProccntUsage;//全局模块的使用计数(与GlblcntUsage相同)。通常这一项也是没有意义的,被设置为0xFFFF。
BYTE *modBaseAddr;//模块的基址,在其所属的进程范围内。
DWORD modBaseSize;//模块的大小,单位字节。
HMODULE hModule;//所属进程的范围内,模块句柄。
TCHAR szModule[MAX_PATH];//NULL结尾的字符串,其中包含模块名。
TCHAR szExePath[MAX_PATH];//NULL结尾的字符串,其中包含的位置,或模块的路径。
} MODULEENTRY32, *PMODULEENTRY32, *LPMODULEENTRY32; // 别名
CreateToolhelp32Snapshot
CreateToolhelp32Snapshot
可以通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照。函数原型:
1
2
3
4 >HANDLE WINAPI CreateToolhelp32Snapshot(
>DWORD dwFlags, //用来指定“快照”中需要返回的对象,可以是TH32CS_SNAPPROCESS等
>DWORD th32ProcessID //一个进程ID号,用来指定要获取哪一个进程的快照,当获取系统进程列表或获取 当前进程快照时可以设为0
>);dwFlags
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 >指定快照中包含的系统内容,这个参数能够使用下列数值(常量)中的一个或多个。
>TH32CS_INHERIT(0x80000000) - 声明快照句柄是可继承的。
>TH32CS_SNAPALL - 在快照中包含系统中所有的进程和[线程](https://baike.baidu.com/item/线程/103101)。
>TH32CS_SNAPHEAPLIST(0x00000001) - 在快照中包含在th32ProcessID中指定的进程的所有的堆。
>TH32CS_SNAPMODULE(0x00000008) - 在快照中包含在th32ProcessID中指定的进程的所有的模块。
>TH32CS_SNAPPROCESS(0x00000002) - 在快照中包含系统中所有的进程。
>TH32CS_SNAPTHREAD(0x00000004) - 在快照中包含系统中所有的线程
>H32CS_SNAPALL = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE)th32ProcessID
1 >指定将要快照的进程ID。如果该参数为0表示快照当前进程。该参数只有在设置了TH32CS_SNAPHEAPLIST或者TH32CS_SNAPMODULE后才有效,在其他情况下该参数被忽略,所有的进程都会被快照。
Module32First
此函数检索与进程相关联的第一个模块的信息
1
2
3
4 >BOOL WINAPI Module32First(
>HANDLE hSnapshot,
>LPMODULEENTRY32 lpme
>);参数
hSnapshot
调用
CreateToolhelp32Snapshot
函数返回的快照句柄
lpmeMODULEENTRY32
结构的指针。用来返回数据返回值
成功返回TRUE失败返回FALSE
CloseHandle
关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等。在
CreateThread
成功之后会返回一个hThread
的handle
,且内核对象的计数加1,CloseHandle
之后,引用计数减1,当变为0时,系统删除内核对象。
1
2
3
4
5
6
7
8
9
10 >方法名称:CloseHandle
>位置:Kernel32.dll
>BOOL CloseHandle(
>HANDLE hObject
>);
>参数
>hObject :代表一个已打开对象handle。
>返回值
>TRUE:执行成功;
>FALSE:执行失败,可以调用GetLastError()获知失败原因。返回值
Long
,非零表示成功,零表示失败。会设置GetLastError
参数表
参数 类型及说明
hObject Long
,欲关闭的一个对象的句柄注解
除非对内核对象的所有引用都已关闭,否则该对象不会实际删除
Module32Next
此函数检索有关与进程或线程关联的下一个模块的信息。
1
2
3
4 >BOOL WINAPI Module32Next(
>HANDLE hSnapshot,
>LPMODULEENTRY32 lpme
>);参数
- hSnapshot
[in]处理上一次调用CreateToolhelp32Snapshot函数所返回的快照。- lpme
[out]指向MODULEENTRY32结构的指针。返回值
TRUE表示模块列表的下一个条目已复制到缓冲区。FALSE表示失败。GetLastError返回的ERROR_NO_MORE_FILES错误值指示没有更多的模块。
1
代码
一开始我是用Python3写的,但是当代码执行到Module32First
时候,就会发生报错
1 | def GetProcessImageBase(ProcessId,moduleName): |
通过搜索引擎搜索了很久,也没解决,ret
执行过后变成了0,但是 hModuleSnap
不是空值,me32
也没问题,到底是为什么我也不清楚了。
后面,我改成Python2来执行这行代码,竟然发现没有报错,惊了。
1.导入库
1 | # -*- coding:utf-8 -*- |
2.定义结构体
1 | class PROCESS_BASIC_INFORMATION(ctypes.Structure): |
3.声明全局变量
1 | kernel32 = ctypes.windll.LoadLibrary("kernel32.dll")#声明kernel32 |
4.代码编写
1 | def GetProcessImageBase(ProcessId,moduleName): |
5.调用
1 | def main(): |
6.完整代码
1 | # -*- coding:utf-8 -*- |
Python32 位 模块遍历完整代码
1 | from win32gui import FindWindow #获取窗口句柄 |
来源:python制作游戏脚本之网游寻址及64位程序的模块遍历(视频已安排)
如果不能转载的话,评论一下我就删了,我看原贴好像没有禁止转载。
后续
直到后面研究才发现,是Python64位和32位的问题,所以不是代码问题,是版本问题,那就没办法了。 卸载64位,安装32位。
Python3 获取指定模块基址代码
1 | # -*- coding:utf-8 -*- |
Python2 获取指定模块基址
1 | # -*- coding:utf-8 -*- |
结语
借用一句看到很不错的话:
技术不分对错.人性才分善恶.
学习逆向的人必须身心放正.
身心放正之人手握屠龙刀,也是保家卫民.