QT框架软件及其中tcp/udp网络逆向分析要点记录

一. 概述

前一段时间有逆向分析一个windows系统上QT5的软件,要获取其中显示界面中对应数据生成方式。在分析过程中额外去了解QT框架的相关知识是必不可少的,最主要的一点是信号和槽函数怎么对应起来,以及QT中自封装的数据结构怎么处理。框架分析的难点是除了分析基本功能外,还得分析框架自身的API和框架常见的特征,只有这样才能更好地定位功能代码,但只要分析一次,后面如果是碰到相同的框架,则能很快上手。下面对QT框架分析心得做个简单记录。

二. 信号和槽函数的定位

信号与槽函数 对应 Activate 和 connect ,他们有一个参数是一样的,可以通过这个对应上,从而找到信号对应槽函数。正常开发时,信号和槽函数的注册不是Activate 和 connect,但编译生成的可执行文件导入到ida中会看到这两个函数。可以通过 frida hook这两个函数,打印参数和调用堆栈,来确定信号和槽函数对应关系及在代码中位置。

三. QT 中常用数据类型处理

QT 中常用数据类型有QString,QVector等,想以字符串或基本数据类型打印出来,就需要了解这些数据类型的结构,因为有时返回内容直接是这些类型的结构体,而不是指针,所以在frida hook中也要做额外处理,类似std::string类型在frida中打印。不过我也没有分析这些的数据类型结构,我是自己用QT直接编译了一个动态库(版本最好和软件的QT框架库对应,这里如果是可执行文件也可以),其中加入了QString,QVector等转基础数据类型的函数,然后将这个动态库用frida加载,然后找到对应的函数地址,并定义成frida函数,在frida中调用这些函数来转化基础数据类型,如下:

var func_QString2charptr = null
var func_QStringLength = null
var func_QVector2doublePtrr = null
var func_QVectorLength = null
var func_QVariant2QString = null
var func_QVariantLength = null
var func_QVariant2charptr = null
var func_QVariant2charptr2 = null
function use_self_dll(){if (func_QString2charptr == null){var module = Module.load("D:\\UseForFrida.dll"); // 这里替换成自实现的dll,函数在dll中实现var addr_QString2charptr = module.getExportByName("_ZN11UseForFrida15QString2charptrER7QStringPcj");var addr_QStringLength = module.getExportByName("_ZN11UseForFrida13QStringLengthER7QString");var addr_QVector2doublePtrr = module.getExportByName("_ZN11UseForFrida17QVector2doublePtrER7QVectorIdEPdi");var addr_QVectorLength = module.getExportByName("_ZN11UseForFrida13QVectorLengthER7QVectorIdE");var addr_QVariant2QString = module.getExportByName("_ZN11UseForFrida16QVariant2QStringER8QVariant");var addr_QVariantLength = module.getExportByName("_ZN11UseForFrida14QVariantLengthER8QVariant");var addr_QVariant2charptr = module.getExportByName("_ZN11UseForFrida16QVariant2charptrER8QVariantPcj");var addr_QVariant2charptr2 = module.getExportByName("_ZN11UseForFrida16QVariant2charptrER8QVariant");func_QString2charptr = new NativeFunction(addr_QString2charptr, 'void', ['pointer','pointer','int']);func_QStringLength = new NativeFunction(addr_QStringLength, 'int', ['pointer']);func_QVector2doublePtrr = new NativeFunction(addr_QVector2doublePtrr, 'void', ['pointer','pointer','int']);func_QVectorLength = new NativeFunction(addr_QVectorLength, 'int', ['pointer']);func_QVariant2QString = new NativeFunction(addr_QVariant2QString, 'pointer', ['pointer']);func_QVariantLength = new NativeFunction(addr_QVariantLength, 'int', ['pointer']);func_QVariant2charptr = new NativeFunction(addr_QVariant2charptr, 'void', ['pointer','pointer','int']);func_QVariant2charptr2 = new NativeFunction(addr_QVariant2charptr2, 'pointer', ['pointer']); //这里函数便可以拿来使用}console.log(func_QString2charptr, func_QStringLength, func_QVector2doublePtrr, func_QVectorLength, func_QVariant2charptr, func_QVariantLength, func_QVariant2charptr2);
}

四. 额外记录下软件中网络方面分析

通过wireshark对那个软件进行抓包,发现也没有https的包,大多是tcp和udp的包。为了定位这些发包和接受包的位置,只需要对系统库中网络接发包相关api进行hook就能定位到对应代码位置。要知道是那个系统库中哪些api处理了这些发包和接收包,可以在网上搜。或者用一种更准确的方法,自己在对应的操作系统(我这里是windows)上用socket写简单的tcp和udp通信的demo,然后用调试器(gdb,windows上更好的是x64dbg)调试自己写的demo,跟到系统库,看是哪些库及那些api处理了底层socket的发送和接收数据。

windows上是 ws2_32.dll 的 closesocket,connect,getpeername,getsockname,htons,inet_ntoa,recv,recvfrom,send,sendto,WSAConnect,WSAConnectByList,WSAConnectByNameA,WSAConnectByNameW,WSARecv,WSARecvDisconnect,WSARecvFrom,WSASend,WSASendDisconnect,WSASendMsg,WSASendTo 等,可以使用frida hook对应的api,打印socket ip和端口,及recv、send、connect等的代码位置。

function hook_win_socketabout(){// var modules = Process.enumerateModules();// for (var i = 0; i < modules.length; i++){//   console.log(modules[i].name, modules[i].base);// }var module = Process.getModuleByName("ws2_32.dll");//analysis ip port// htons   // inet_ntoa// getsockname// getpeernamevar addr_htons = module.getExportByName("htons");var addr_inet_ntoa = module.getExportByName("inet_ntoa");var addr_getsockname = module.getExportByName("getsockname");var addr_getpeername = module.getExportByName("getpeername");// console.log("addr_htons", addr_htons, "addr_inet_ntoa", addr_inet_ntoa, // "addr_getsockname", addr_getsockname, "addr_getpeername", addr_getpeername);var getpeername = new NativeFunction(addr_getpeername, "int", ["int", "pointer", "pointer"]);var getsockname = new NativeFunction(addr_getsockname, "int", ["int", "pointer", "pointer"]);//  var symbols = module.enumerateExports();var addr_connect = module.getExportByName("connect");var addr_recv = module.getExportByName("recv");var addr_send = module.getExportByName("send");var addr_closesocket = module.getExportByName("closesocket");var htons = new NativeFunction(addr_htons, "uint16", ["uint16"]);var inet_ntoa = new NativeFunction(addr_inet_ntoa, "pointer", ["uint32"]);Interceptor.attach(addr_connect, {onEnter:function(argvs){//console.log("Come", "addr_connect", addr_connect);//connect(clntSock, (SOCKADDR*)& sockAddr, sizeof(SOCKADDR));var sockAddr = ptr(argvs[1]);var type = sockAddr.readS16();var port_bf_turn = sockAddr.add(2).readS16();var ip_bf_turn = sockAddr.add(4).readS32();var port_af_turn = htons(port_bf_turn);var ip_af_turn = inet_ntoa(ip_bf_turn);console.log("connect server ---> ", "type:", type, "server ip:", ip_af_turn.readCString(), "port:", port_af_turn);console.log('socket connect called from:\n' +Thread.backtrace(this.context, Backtracer.FUZZY).map(DebugSymbol.fromAddress).join('\n') +'\n');},onLeave:function(retvalue){//retvalue.replace()}});//follow 3   get  server client  ip  port// getsockname(clntSock, (struct sockaddr *)&connectedAddr, &connectedAddrLen);//获取connfd表示的连接上的本地地址// printf("connected server address = %s:%d\n", inet_ntoa(connectedAddr.sin_addr), htons(connectedAddr.sin_port)); //本地ip和端口// getpeername(clntSock, (struct sockaddr *)&peerAddr, &peerLen); //获取connfd表示的连接上的对端地址// printf("connected peer address = %s:%d\n", inet_ntoa(peerAddr.sin_addr), htons(peerAddr.sin_port)); //远程ip和端口Interceptor.attach(addr_recv, {onEnter:function(argvs){//console.log("Come", "addr_recv", addr_recv);var clntSock = argvs[0].toInt32();var localSockAddr = Socket.localAddress(clntSock);var remoteSockAddr = Socket.peerAddress(clntSock);if (localSockAddr != null && remoteSockAddr != null){console.log("socket recv ---> ", "localSockAddr", localSockAddr.ip, localSockAddr.port, "remoteSockAddr", remoteSockAddr.ip, remoteSockAddr.port);}console.log('socket recv called from:\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') +'\n');},onLeave:function(retvalue){//retvalue.replace()console.log("recv ret len", retvalue);}});Interceptor.attach(addr_send, {onEnter:function(argvs){//console.log("Come", "addr_send", addr_send);var clntSock = argvs[0].toInt32();var localSockAddr = Socket.localAddress(clntSock);var remoteSockAddr = Socket.peerAddress(clntSock);if (localSockAddr != null && remoteSockAddr != null){console.log("socket send ---> ", "localSockAddr", localSockAddr.ip, localSockAddr.port, "remoteSockAddr", remoteSockAddr.ip, remoteSockAddr.port);}console.log('socket send called from:\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') +'\n');},onLeave:function(retvalue){//retvalue.replace()}});Interceptor.attach(addr_closesocket, {onEnter:function(argvs){//console.log("Come", "addr_closesocket", addr_closesocket);var clntSock = argvs[0].toInt32();var localSockAddr = Socket.localAddress(clntSock);var remoteSockAddr = Socket.peerAddress(clntSock);if (localSockAddr != null && remoteSockAddr != null){console.log("closesocket ---> ", "localSockAddr", localSockAddr.ip, localSockAddr.port, "remoteSockAddr", remoteSockAddr.ip, remoteSockAddr.port);}console.log('closesocket called from:\n' +Thread.backtrace(this.context, Backtracer.FUZZY).map(DebugSymbol.fromAddress).join('\n') +'\n');},onLeave:function(retvalue){//retvalue.replace()}});var WSAConnect = module.getExportByName("WSAConnect");Interceptor.attach(WSAConnect, {onEnter:function(argvs){// console.log("Come", "WSAConnect", WSAConnect);var sockAddr = ptr(argvs[1]);var type = sockAddr.readS16();var port_bf_turn = sockAddr.add(2).readS16();var ip_bf_turn = sockAddr.add(4).readS32();var port_af_turn = htons(port_bf_turn);var ip_af_turn = inet_ntoa(ip_bf_turn);console.log("WSAConnect server ---> ", "type:", type, "server ip:", ip_af_turn.readCString(), "port:", port_af_turn);console.log('socket WSAConnect called from:\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') +'\n');},onLeave:function(retvalue){}});var WSARecv = module.getExportByName("WSARecv");Interceptor.attach(WSARecv, {onEnter:function(argvs){// console.log("Come", "WSARecv", WSARecv);var clntSock = argvs[0].toInt32();var localSockAddr = Socket.localAddress(clntSock);var remoteSockAddr = Socket.peerAddress(clntSock);if (localSockAddr != null && remoteSockAddr != null){console.log("WSARecv ---> ", "localSockAddr", localSockAddr.ip, localSockAddr.port, "remoteSockAddr", remoteSockAddr.ip, remoteSockAddr.port);}console.log('WSARecv called from:\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') +'\n');},onLeave:function(retvalue){}});var WSARecvFrom = module.getExportByName("WSARecvFrom");Interceptor.attach(WSARecvFrom, {onEnter:function(argvs){// console.log("Come", "WSARecvFrom", WSARecvFrom);var clntSock = argvs[0].toInt32();var localSockAddr = Socket.localAddress(clntSock);var remoteSockAddr = Socket.peerAddress(clntSock);if (localSockAddr != null && remoteSockAddr != null){console.log("WSARecvFrom ---> ", "localSockAddr", localSockAddr.ip, localSockAddr.port, "remoteSockAddr", remoteSockAddr.ip, remoteSoc33446kAddr.port);}console.log('WSARecvFrom called from:\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') +'\n');},onLeave:function(retvalue){}});var WSASend = module.getExportByName("WSASend");Interceptor.attach(WSASend, {onEnter:function(argvs){// console.log("Come", "WSASend", WSASend);var clntSock = argvs[0].toInt32();var localSockAddr = Socket.localAddress(clntSock);var remoteSockAddr = Socket.peerAddress(clntSock);if (localSockAddr != null && remoteSockAddr != null){console.log("WSASend ---> ", "localSockAddr", localSockAddr.ip, localSockAddr.port, "remoteSockAddr", remoteSockAddr.ip, remoteSockAddr.port);}console.log('WSASend called from:\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') +'\n');},onLeave:function(retvalue){}});}

当时分析时,有一个端口的数据通过wireshark抓到后,在程序中一直hook不到,后来发现是在子进程中实现的tcp通信,然后通过内存映射和主进程进行数据共享。

五. 小结

记地有点简单,因为只有之前电脑环境上有那个分析的软件及安装了QT框架,所以这里也没有贴出QT相关代码,只记录了一些思路。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/17735.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

coredump文件生成配置

1.打开coredump文件生成开关 查看开关是否打开&#xff1a;ulimit -a 如果core file size 为0&#xff0c;则为关闭。 执行&#xff1a;ulimit -c 10240 将其coredump文件大小设置。 2.coredump文件保存位置&#xff1a; /proc/sys/kernel/core_pattern文件可以控制core文…

骨折分类数据集1129张10类别

数据集类型&#xff1a;图像分类用&#xff0c;不可用于目标检测无标注文件 数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;1129 分类类别数&#xff1a;10 类别名称:["avulsion_fracture",…

鸿蒙OS开发:【一次开发,多端部署】(导航栏) 导航栏

一多导航栏 介绍 本示例展示了导航组件在不同设备形态下的样式。 在sm设备上&#xff0c;以tabs形式展示&#xff0c;内容、导航为上下样式布局&#xff0c;通过点击底部tabs切换内容&#xff1b;在md/lg设备上&#xff0c;以[SideBarContainer]形式展示&#xff0c;内容、导…

RocketMQ学习(1) 快速入门

mq的一些前置知识和概念知识可以看这篇文章——SpringCloud入门(3) RabbitMQ&#xff0c;比如常见mq的对比等等&#xff0c;这篇文章不再赘述。 目录 RocketMQ概念、安装与配置docker配置 RocketMQ快速入门**同步消息消费模式 **异步消息*单向消息**延迟消息*顺序消息批量消息事…

大工作量LUAD代谢重编程模型多组学(J Transl Med)

目录 1&#xff0c;单细胞早期、晚期和转移性 LUAD 的细胞动力学变化 2&#xff0c;细胞代谢重编程介导的LUAD驱动恶性转移的异质性 3&#xff0c;模型构建 S-MMR评分管线构建 4&#xff0c;S-MMR 模型的预后评估 5&#xff0c; 还开发了S-MMR 评分网络工具 6&#xff0c…

Test-Preparation Phase 测试准备阶段介绍

测试准备阶段是确保测试过程顺利进行的基础阶段,对于DRAM(动态随机存取存储器)等复杂产品的测试尤为重要。以下是Test-Preparation Phase中关于Fault modeling(故障建模)、Test generation(测试数据生成)、Fault simulation(故障模拟)以及DFT&DFM(测试设计与可制…

Windows 使用技巧

Windows 使用技巧 ①局域网内共享文件 ②CTRL Y 和 CTRL Z ①局域网内共享文件 第一步&#xff1a; 选择要共享的文件&#xff08;分享方操作&#xff09; 第二步&#xff1a; 右键打开属性&#xff0c;选择共享&#xff08;分享方操作&#xff09; 第三步&#xff1a; …

k8s集群配置普通用户权限

集群管理员&#xff1a;负责管理 Kubernetes 集群的用户&#xff0c;拥有最高权限&#xff0c;可以对集群中的资源进行任何操作。 开发者&#xff1a;在 Kubernetes 集群中部署和管理自己的应用&#xff0c;可能有限制的权限&#xff0c;仅能管理特定的命名空间或资源。 第三…

简单得阴影引导实现

效果如下: 实现方式&#xff1a; 1、引入三方库&#xff1a; implementation io.github.razerdp:BasePopup:3.2.0 2、代码实现 class NewUserGuide3Popup : BasePopupWindow {constructor(activity: Activity) : super(activity)constructor(context: Context) : super(con…

js检验一个字符串是否是正确时间格式的工具方法

js检验一个字符串是否是正确时间格式的工具方法 (()> {/*** 检验字符串是否为时间格式* param {String} date 需要检验的时间格式* returns true 为时间格式&#xff0c;false 为非时间格式*/const isTimaFormat (date) > {if(!date) return false;try{const tempTime …

基于maxkey接入jeecgboot并实现账户同步

1. 注册应用 1.1 在统一认证中心注册第三方应用 1.1.1 填写应用名和登录地址 1.1.2 填写认证地址授权方式和作用域 1.1.3 选择权限范围并提交 1.2 配置访问权限 1.2.1 指定用户组 1.1.2 选择注册的应用 1.1.3 在单点登录认证页面查看添加的应用 1.3 同步一个第三方应用的账号…

VolWeb:集中式增强型数字取证内存分析平台

关于VolWeb VolWeb是一款最新开发的集中式增强型数字取证内存分析平台&#xff0c;该平台基于Volatility 3框架实现其功能&#xff0c;该工具旨在辅助广大研究人员执行安全分析和事件应急响应等任务。 VolWeb可以提供集中式、可视化的增强型网络应用程序&#xff0c;并提高安全…

详解 Scala 的泛型

一、协变与逆变 1. 说明 协变&#xff1a;Son 是 Father 的子类&#xff0c;则 MyList[Son] 也作为 MyList[Father] 的 “子类”逆变&#xff1a;Son 是 Father 的子类&#xff0c;则 MyList[Son] 作为 MyList[Father] 的 “父类”不变&#xff1a;Son 是 Father 的子类&…

车机壁纸生成解决方案,定制化服务,满足个性化需求

在数字化与智能化浪潮的推动下&#xff0c;汽车内部设计已不再仅仅满足于基本功能的需求&#xff0c;更追求为用户带来前所未有的视觉享受与沉浸式体验。美摄科技&#xff0c;凭借其在图像生成与处理领域的深厚积累&#xff0c;推出了一款创新的车机壁纸生成解决方案&#xff0…

【FISCO BCOS】二十一、JAVA与FISCO BCOS交互(节点前置篇)

目录 一、准备链和节点前置服务 二、准备合约 三、新建java工程 四、参照API官方

上海市计算机学会竞赛平台2022年10月月赛丙组算式求值(一)

题目描述 给定一个由正整数、加号、减号构成的表达式&#xff0c;请计算表达式的值。 输入格式 输入一个由 正整数、、- 构成的表达式 输出格式 单个整数&#xff1a;表示算式的值。 数据范围 数据保证 输入的字符串长度不超过 100,000100,000&#xff0c;其中出现的每…

代码随想录——左叶子之和(Leetcode404)

题目链接 BFS 队列 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right)…

磁珠笔记汇总

磁珠笔记汇总 磁珠是和电感很相似的器件。 电感磁珠单位亨(H)欧姆(Ω)是否储能存储能量消耗高频能量应用场景通常用于开关电源吸收高频&#xff0c;EMC保护如何看待损耗使用电感时希望损耗越小越好使用磁珠时是利用其损耗来消耗不需要的高频分量 一、磁珠的工作原理 磁珠与…

力扣刷题--2956. 找到两个数组中的公共元素【简单】

题目描述 给你两个下标从 0 开始的整数数组 nums1 和 nums2 &#xff0c;它们分别含有 n 和 m 个元素。 请你计算以下两个数值&#xff1a; 统计 0 < i < n 中的下标 i &#xff0c;满足 nums1[i] 在 nums2 中 至少 出现了一次。 统计 0 < i < m 中的下标 i &am…

【Linux】解决误操作libc.so.6导致的问题,补充:升级glibc注意事项

千万不要轻易动/usr/lib64/libc.so.6。 glibc是Linux系统中最底层的api&#xff0c;Linux几乎所有运行库都依赖glibc。/usr/lib64/libc.so.6属于glibc&#xff0c;在centos7中是个软链接。 一旦误删或误操作libc.so.6&#xff0c;或者glibc新版本不兼容等原因&#xff0c;都可…