当前位置: 首页 > news >正文

【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: file

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

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

import ctypeskernel32 = 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))

file

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

而调用stdcall_add和它基本一样,将 ctypes.CFUNCTYPE改成ctypes.WINFUNCTYPE即可 file

构建结构体并调用函数

接着我们开始调用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))

效果如下: file

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

在命令里输入dump 0x1570d40或者打开帮助->计算器,输入这个地址,然后在内存窗口打开: file

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

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

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

调用成功,说明结构体构造的没问题: file

读取内存中的全局结构体

一样是先计算偏移

# 全局变量的内存地址一般偏移是固定的,如果是函数内的局部变量就不能这么计算了
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)

执行结果如下图: file

调用回调函数

先定义一个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)

执行结果: file

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

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

https://github.com/kanadeblisst00/PyRobot-part3

相关文章:

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

目录修整 目前的系列目录(后面会根据实际情况变动): 在windows11上编译python将python注入到其他进程并运行注入Python并使用ctypes主动调用进程内的函数和读取内存结构体使用汇编引擎调用进程内的任意函数利用beaengine反汇编引擎的c接口写一个pyd库&#xff0c;用于实现inl…...

easyExcel按模板填充数据,处理模板列表合并问题等,并导出为html,pdf,png等格式文件demo

1.工具类 /*** excle模板填充并转换html* * @param response 返回* @param order 主体内容* @param goods 配件列表* @param pro 项目列表* @throws IOException*/public static void moudleExcleToHtml(HttpServletResponse response, String moudleUrl, Object o…...

怎么开发小程序?微信小程序开发方式

小程序开发之所以受到欢迎&#xff0c;是因为相比于APP&#xff0c;小程序的开发成本更低。不需要下载和安装&#xff0c;用户可以直接在微信内使用&#xff0c;节省了开发和维护的成本。小程序的开发方式有很多种&#xff0c;常见的有&#xff1a;自己源码开发、模板编辑、购买…...

测试从外包到自研再到大厂,这5年鬼知道我是怎么过来的

18岁那年我背井离乡来到从来没有来过的郑州。在一所普通的二本院校里学网络工程。 很明显&#xff0c;在大学以前只会用电脑开关机打LOL的我恍然间只觉得自己来到了人间天堂&#xff0c;没有人管&#xff0c;也没有任何烦恼无忧无虑的过了三年大学生涯。 直到秋招的开始&…...

Stable Diffusion系列(二):ControlNet基础控件介绍

文章目录 线稿提取类Canny&#xff1a;边缘检测SoftEdge&#xff1a;软边缘检测Lineart&#xff1a;精细线稿提取Scribble/Sketch&#xff1a;涂鸦提取MLSD&#xff1a;建筑领域的线条提取 3D提取类Normal map&#xff1a;法线贴图Depth&#xff1a;深度计算Segmentation&#…...

sql server数据库跟踪——SQL Server Profiler解析

工具&#xff1a; SQL Server Profiler这个工具是SQL Server数据库自带的语句执行跟踪工具&#xff0c;常使用于分析软件修改数据库时所执行的语句&#xff0c;适合用来研究软件运行数据库的原理。 打开方式&#xff1a; 本机安装了SQL server的话&#xff0c;都是自带的。直接…...

多机多卡分布式训练

1. 环境搭建 分布式训练框架&#xff1a;acceleratedeepspeedpdsh(可有可无)基础环境&#xff1a;cuda、显卡驱动、pytorch 1.1 安装相关包 cuda安装&#xff1a;参考官网安装步骤 wget https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda-…...

打字练习软件 Type Fu mac中文版技能介绍

Type Fu mac是一款打字练习和提高打字速度的应用程序。它旨在帮助用户通过练习键盘打字&#xff0c;提高打字准确性和速度。无论您是初学者还是想要提高打字技能的专业人士&#xff0c;Type Fu都是一个很好的选择&#xff01; Type Fu mac采用了一种互动&#xff0c;游戏化的方…...

我的云栖大会之旅:见证云计算创新的15年

云栖大会&#xff0c;曾经是一次不可思议的科技之旅&#xff0c;却如今已见证了我对云计算世界的15年关注和发展。第一次踏上云栖大会之旅&#xff0c;我记得是在2009年。那时的云计算还是一个新生事物&#xff0c;而云栖大会正是其中的奠基石。 我清楚地记得那个炎热的夏天&am…...

一个小技巧,显著提升大模型推理能力!加州大学提出MAF多反馈框架

作者 | 谢年年 最近&#xff0c;多篇文章《GPT-4的推理能力非常有限&#xff0c;有两篇论文为证》、《DeepMind&#xff1a;无法自我纠正推理&#xff0c;除非提前得知正确答案》指出大模型在推理任务中似乎没有自我改进的能力。即在无任何外部反馈的情况下无法通过自我纠正的形…...

测开 (Junit 单元测试框架)

目录 了解 Junit 引入相关依赖 1、Junit注解 Test BeforeEach、BeforeAll AfterEach && AfterAll 2、断言 1、Assertions - assertEquals 方法 2、Assertions - assertNotEquals 方法 3、Assertions - assertTrue && assertFalse方法 4、Assertions…...

ncurse编程指南

文章目录 0. 介绍1. Hello, Ncurse2. 初始化函数2.1 raw() 和 cbreak()2.2 echo()和noecho()2.3 keypad()2.4 halfdelay()2.5 初始化样例 3. 命名规范4. 输出函数4.1 addch()类函数4.2 printw()类函数4.3 addstr()类函数4.4 注意4.5 输出函数例子 5. 输入函数5.1 getch()5.2 sc…...

Graph U-Net Code【图分类】

1. main.py # GNet是需要用到的model net GNet(G_data.feat_dim, G_data.num_class, args) # graph, 特征维度&#xff0c;类别数&#xff0c;参数 trainer Trainer(args, net, G_data) #开始训练数据 # 正式开始训练数据 trainer.train()2. network.py class GNet(nn.Modul…...

PTA 秀恩爱分得快(树)

题目 古人云&#xff1a;秀恩爱&#xff0c;分得快。 互联网上每天都有大量人发布大量照片&#xff0c;我们通过分析这些照片&#xff0c;可以分析人与人之间的亲密度。如果一张照片上出现了 K 个人&#xff0c;这些人两两间的亲密度就被定义为 1/K。任意两个人如果同时出现在…...

文心一言4.0对比ChatGPT4.0有什么优势?

目录 总结 文心一言4.0的优势 文心一言4.0的劣势 免费分享使用工具 后话 生成式AI的困境 “不会问”“不会用”“不敢信” 为什么要出收费版本&#xff1f; 目前使用过国内的文心一言3.5和WPS AI&#xff0c;国外的ChatGPT4.0。 文心一言和其他国内产品相比&#xff0…...

美观且可以很方便自定义的MATLAB绘图颜色

函数介绍 主函数是draw_test&#xff0c;用于测试函数。 draw_h是函数&#xff0c;用于给Matlab提供美观且可以很方便自定义的绘图颜色。 draw_h函数介绍 这是一个带输入输出的函数&#xff0c;输入1/2/3&#xff0c;输出下面三种颜色库的配色&#xff0c;每种库均有五种颜色…...

基于jsp,ssm物流快递管理系统

开发工具&#xff1a;eclipse&#xff0c;jdk1.8 服务器&#xff1a;tomcat7.0 数据库&#xff1a;mysql5.7 技术&#xff1a; springspringMVCmybaitsEasyUI 项目包括用户前台和管理后台两部分&#xff0c;功能介绍如下&#xff1a; 一、用户(前台)功能&#xff1a; 用…...

陪诊系统|挂号陪护搭建二开陪诊师入驻就医小程序

我们的陪诊小程序拥有丰富多样的功能&#xff0c;旨在最大程度满足现代人的需求。首先&#xff0c;我们采用了智能排队系统&#xff0c;通过扫描二维码获取排号信息&#xff0c;让您从繁琐的排队过程中解放出来。其次&#xff0c;我们提供了多种支付方式&#xff0c;不仅可以实…...

恒驰服务 | 华为云数据使能专家服务offering之大数据建设

恒驰大数据服务主要针对客户在进行智能数据迁移的过程中&#xff0c;存在业务停机、数据丢失、迁移周期紧张、运维成本高等问题&#xff0c;通过为客户提供迁移调研、方案设计、迁移实施、迁移验收等服务内容&#xff0c;支撑客户实现快速稳定上云&#xff0c;有效降低时间成本…...

轻量级狂雨小说cms系统源码 v1.5.2 基于ThinkPHP5.1+MySQL

轻量级狂雨小说cms系统源码 v1.5.2 基于ThinkPHP5.1MySQL的技术开发 狂雨小说cms提供一个轻量级小说网站解决方案&#xff0c;基于ThinkPHP5.1MySQL的技术开发。 KYXSCMS,灵活&#xff0c;方便&#xff0c;人性化设计简单易用是最大的特色&#xff0c;是快速架设小说类网站首选…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...