【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体

这篇具有很好参考价值的文章主要介绍了【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录修整

目前的系列目录(后面会根据实际情况变动):

  1. 在windows11上编译python
  2. 将python注入到其他进程并运行
  3. 注入Python并使用ctypes主动调用进程内的函数和读取内存结构体
  4. 使用汇编引擎调用进程内的任意函数
  5. 利用beaengine反汇编引擎的c接口写一个pyd库,用于实现inline hook
  6. 利用beaengine反汇编引擎的python接口写一个py库,用于实现inline hook
  7. 注入python到微信实现简单的收发消息
  8. Bug修复和细节优化,允许Python加载运行py脚本并且支持热加载
  9. 读取微信内存中的好友联系人列表的信息结构体数据
  10. 做一个僵尸粉检测工具
ctypes的主要功能

ctypes是Python与c写的文件做交互的库,能和Python直接交互的也就是动态库了。所以在Windows上主要是调用dll,Linux上则是调用so。

不过,在这个系列文章里,它的作用稍微有些不同。因为Python已经被注入到其他进程,可以用ctypes随意操作其他进程的数据和调用其他进程里的函数,相对于用c写的dll注入后,只需要把c的接口改成Python的。这样就能动态操作,不需要频繁改动dll代码,注入卸载了

同时它还能调用其他进程里的任意函数,不过默认只能调用stdcallcdecl两种调用约定的函数。如果不是这两种调用约定,则需要使用内联汇编来调用。当然Python无法直接内联汇编,但可以通过汇编引擎将汇编指令翻译成机器能识别的机器码写入到内存,达到内联汇编的效果。也可以不用汇编引擎,直接写机器码到内存,只要你能记得汇编指令代表的机器码(人肉汇编引擎)。

与进程交互

对于调用dll相关的功能,我这里就不多赘述了,之前写的一篇文章里有:Python基础库-ctypes

这里我主要说下ctypes与进程交互方面,比如读取内存结构体,调用内存中的函数等

写一个测试程序

先自己写一个测试程序,然后在自己的程序测试,这样可以避免很多错误,也方便调试。简单写了几个函数和结构体测试,代码如下:

typedef int(*cdecl_add_pointer)(int, int);
typedef int(__stdcall *stdcall_add_pointer)(int, int);

struct CString
{
    wchar_t* s = nullptr;
    size_t len = 0;
    CString(wchar_t* ss) {
        s = ss;
        len = wcslen(ss);
    }
};

CString ccs((wchar_t*)L"aaaaaa这是个全局变量结构体");

int cdecl_add(int a, int b) {
    std::wcout << L"cdecl调用约定\n";
    return a + b;
}

int __stdcall stdcall_add(int a, int b) {
    std::wcout << L"stdcall调用约定\n";
    return a + b;
}

int add_callback(stdcall_add_pointer add, int a, int b) {
    std::wcout << L"add_callback \n";
    return add(a, b);
}

int console_print(CString* cs) {
    std::wcout << L"print CString: ";
    std::wcout << cs->s;
    std::wcout << L"\n";
    return cs->len;
}
调用进程内的函数

这里就用上一篇的pyexe.dll来将Python注入到目标进程。

现在开始调用cdecl_add和stdcall_add这两个函数,首先需要找到他们的地址偏移,上面的函数里都有一个字符串,这也是我为了方便定位刻意写的。

在x32dbg里搜索字符串,就能定位这两个函数,比如cdecl_add: 【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体,

得出cdecl_add函数的偏移就是00AF4190-00AE0000, 00AE0000是exe的基址。同理可以知道stdcall_add的基址为0x00AF43B0 - 0x00AE0000

先定义一个GetModuleHandleW函数用于获取exe的基址

import ctypes

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
GetModuleHandleW = kernel32.GetModuleHandleW
GetModuleHandleW.argtypes = (ctypes.c_wchar_p, )
GetModuleHandleW.restype = ctypes.c_int
base = GetModuleHandleW("CtypesTest.exe")

以下几行代码就是调用cdecl_add的全部代码,看注释一行一行解释:

# 定义函数指针类型,第一个参数是返回值类型,后面的都是参数类型
cdecl_add_pfunc = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int)
# 函数的偏移
cdecl_add_offset = 0x00AF4190 - 0x00AE0000
# 通过基址和偏移得到当前函数所在内存地址,然后传给cdecl_add_pfunc就能得到这个函数
cdecl_add = cdecl_add_pfunc(base + cdecl_add_offset)
# 传入相应的参数就能调用成功
print("cdecl_add: ", cdecl_add(111, 222))

【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体,

可以看到结果成功输出,也没有报错。没有打印cdecl调用约定是因为我们在注入Python是重定向了stdout,如果想要打印目标进程的输出则需要使用上一篇文章提到的CPython接口重定向stdout。

而调用stdcall_add和它基本一样,将 ctypes.CFUNCTYPE改成ctypes.WINFUNCTYPE即可 【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体,

构建结构体并调用函数

接着我们开始调用console_print,它的参数类型是一个结构体指针,所以要先在Python构建出结构体

ctypes定义结构体代码如下:

class CString(ctypes.Structure):
    _fields_ = [
        ('s', ctypes.c_wchar_p),
        ('len', ctypes.c_uint)
    ]

定义console_print函数:

console_print_pfunc = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.POINTER(CString))
console_print_offset = 0x00AF2F10 - 0x00AE0000
console_print = console_print_pfunc(base + console_print_offset)

创建结构体并赋值

cs = CString()
s = "Python结构体字符串"
cs.s = ctypes.c_wchar_p(s)
cs.len = len(s)

为了确保创建的结构体和目标进程里的一样,可以先在Python控制台创建,然后在x32dbg里查看。

这里我为了避免一直要输入代码,使用import sys;sys.path.append(r"T:\Code\PyRobot\part3\py_code")来将目录添加到sys.path,然后导入我写的代码import testa

如果要重新导入:import importlib;importlib.reload(testa),查看Python构建的结构体内存地址有三种方法:

print("ctypes.byref: ", ctypes.byref(cs))
print("ctypes.addressof: ", hex(ctypes.addressof(cs)))
print("ctypes.cast: ", hex(ctypes.cast(ctypes.pointer(cs), ctypes.c_void_p).value))

效果如下: 【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体,

可以看到cs的内存地址是0x1570d40,然后在x32dbg里查看这个内存地址。

在命令里输入dump 0x1570d40或者打开帮助->计算器,输入这个地址,然后在内存窗口打开: 【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体,

这个地址的内容就是Python构建出的结构体,如果不清楚结构体在内存中长啥样,可以把c代码创建的结构体也打印出来,然后在x32dbg中查看

最后调用这个函数,ctypes.byref的作用是传递指针的引用,ctypes.pointer也可以,它是构造一个新的指针:

result = console_print(ctypes.byref(cs))
print("console_print result: ", result)

调用成功,说明结构体构造的没问题: 【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体,

读取内存中的全局结构体

一样是先计算偏移

# 全局变量的内存地址一般偏移是固定的,如果是函数内的局部变量就不能这么计算了
ccs_offset = 0x00AFE2D0 - 0x00AE0000 
css_addr = base + ccs_offset

然后从地址中读取出结构体里的字符串和整数

s = ctypes.c_wchar_p.from_address(css_addr)
l = ctypes.c_uint.from_address(css_addr + 0x4)
print("单独读取内存结构体: ", s.value, l)

更简单的方法就是直接转为结构体

css = CString.from_address(css_addr)
print("读取整个结构体: ", css.s, css.len)

执行结果如下图: 【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体,

调用回调函数

先定义一个Python回调函数

def python_stdcall_add(a:int, b:int):
    print("python_stdcall_add: ", a, b)
    return a-b

定义add_callback函数

add_callback_pfunc = ctypes.CFUNCTYPE(ctypes.c_int, stdcall_add_pfunc, ctypes.c_int, ctypes.c_int) 
add_callback_offset = 0x00AF40D0 - 0x00AE0000
add_callback = add_callback_pfunc(base + add_callback_offset)

因为回调函数的类型stdcall_add之前已经定义了,这里就直接用了

result = add_callback(stdcall_add_pfunc(python_stdcall_add), 5, 2)
print("add_callback: ", result)

执行结果: 【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体,

本篇就到此结束了,其他更复杂的数据类型在后面的实战中再说。

本篇文章用到的文件和代码

https://github.com/kanadeblisst00/PyRobot-part3文章来源地址https://www.toymoban.com/news/detail-736666.html

到了这里,关于【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • python微信机器人制作教程+源码

    大多数人无法登录网页版,所以饶过它模拟电脑登录,这个模块一定记得安装: python微信机器人 b站:川川菜鸟 前面qq机器人教程也在b站有,关注一下博主吧。 比如给文件传输助手发送消息,并实时监控,代码: 效果如下: 比如要自动给张三发送消息,代码如下: 效果:

    2024年02月13日
    浏览(29)
  • Python基于PC版微信实现机器人

    在 github 中有基于 web 版的微信实现的实时收发消息 api , python 调用起来非常简单。但是目前来说,大部分的用户没法登录 web 版的微信,因此也就没法使用。 今天我们介绍基于 windows 版的微信,实现实时收发信息。本文站在巨人的肩膀上,基于第三方提供的库,实现自动聊

    2023年04月17日
    浏览(27)
  • 微信机器人的构建与使用

    一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055@qq.com Time of completion:2022.12.15 Last edited: 2022.12.17 目录 《微信机器人》程序使用说明 微信机器人使用说明 1.项目说明 2.  系统环境 3.准备条件 4.操作步骤 部分代码: 首先启动 Flask项目 ,然后启动 小米球内

    2024年02月09日
    浏览(31)
  • 运用python实现企业微信群机器人消息推送

    使用场景 :将BI报表精准推送入(群),精准触达用户 目的 :提高管理层对数据的感知度 工具:python+企业微信 步骤: 1、创建企业微信群机器人,提取Webhook地址(群机器人地址) 2、编写代码填充推送内容信息实现推送 3、其他需求自定义代码编写 实现方法1–优化后 实现

    2024年02月16日
    浏览(26)
  • python连接自己的机器人接口在微信聊天

    机器人有连接到数据库,所以可以长记忆对话,多线程可以使得机器人同时和几个好友聊天。将消息发送到远程API进行处理,并回复处理后的消息。脚本还允许为每个好友分配一个唯一的随机 ID,以便跟不同的好友聊天并维护聊天记忆。

    2024年02月09日
    浏览(26)
  • 【Python微信机器人】第一篇:在windows11上编译python

    我打算写一个系列,内容是将python注入到其他进程实现inline hook和主动调用。本篇文章是这个系列的第一篇,后面用到的案例是 注入python到PC微信实现基本的收发消息 。文章着重于python方面的内容,所以对于微信找收发消息的call不会去讲过程,有兴趣的可以直接百度搜 PC微信

    2024年02月08日
    浏览(33)
  • 企业微信机器人WorkTool使用文档

    先附一下官方介绍 源码友情链接 根据产品需求的 落地场景 我这里最看重的是他的自动创建外部群拉入客户和销售,并能用接口查询群聊记录,连企业微信会话存档的费用都省了,把机器人拉群里,@机器人问问题可以预先设置简单的问答库。另一个我看重的功能是自动通过

    2024年02月02日
    浏览(34)
  • JavaDemo——使用机器人发送微信消息

    原理很简单,使用机器人模拟按键,使用剪贴板把内容copy进去发送; 需要先在pc登录微信客户端,然后用机器人按键,使用ctrl+alt+w快捷键打开微信,使用ctrl+f打开搜索,黏贴好友名称进行搜索,然后黏贴要发送的消息发送即可; 此外还需要注意耗时操作,需要等待操作完成

    2024年02月13日
    浏览(34)
  • python上的免费免登录微信智能聊天机器人

    目录  一、准备  二、开始 三、全部代码 四、总结  一、准备 需要bs4库、requests库、time库(python自带)、wxauto库。 如果没有的话请用pip安装。 在本示例中,使用的是wxauto,所以只能识别桌面上显示的微信窗口,一旦微信窗口最小化,便无法使用。解决办法:可以在GitHub上

    2023年04月08日
    浏览(31)
  • Python实现企业微信群机器人自动化推送

    人工智能(Artificial Intelligence),英文缩写为AI。它是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。 ——《百度百科》 实际工作中,有类似这样的场景, 需要将某些通知信息定期发送到企业微信群,需要将公司某些指标的异

    2024年02月09日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包