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

Windows X86 远线程注入问题解惑

🏆本文收录于《CSDN问答解惑-专业版》专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!

问题描述

  Windows X86 远线程注入问题解惑
¥15
c++
windows
在之前提问的知道下 成功部署了 汇编器 ; 一会即将采纳。
新问题:(请通读全文 重点在于解惑)
下面这个是 X32dbg中 看到的一个功能call 作用是选中一个物体。

0057ADEB | 8B0D 90FB3801          | mov     ecx, dword ptr [138FB90]            |
0057ADF1 | 56                     | push    esi                                 |
0057ADF2 | E8 B9C14A00            | call    A26FB0                              |
0057ADF7 | 8BC8                   | mov     ecx, eax                            |
0057ADF9 | E8 D223FCFF            | call    53D1D0                              | 选中

这个是 我用来 翻译汇编为机器码的相关代码:
该汇编器 默认 地址为绝对地址(直接翻译)。

int QQSG::AsmToHex(ks_arch arch, int mode, const char* assembly, int syntax, QString& outStr, size_t* OutSize) {int status = 0;ks_engine* ks;ks_err err;size_t count;unsigned char* encode = nullptr;size_t size = 0;// Initialize Keystone engineerr = ks_open(arch, mode, &ks);if (err != KS_ERR_OK) {printf("Failed to initialize Keystone engine: %d\n", ks_errno(ks));return -1;}// Set syntax optionif (syntax)ks_option(ks, KS_OPT_SYNTAX, syntax);// Assemble instructionif (ks_asm(ks, assembly, 0, &encode, &size, &count)) {printf("ERROR: failed on ks_asm() with count = %zu, error code = %d\n", count, ks_errno(ks));ks_free(encode); // Free encoded dataks_close(ks);    // Close Keystone enginereturn 2;}// Check if the encoding was successfulif (size > 0) {// Convert machine code to hexadecimal stringfor (size_t i = 0; i < size; i++) {char tmp[5];sprintf(tmp, "%02X", encode[i]);outStr += tmp;}outStr += "\r\n";// Print the machine code for debuggingprintf("Generated machine code: ");for (size_t i = 0; i < size; i++) {printf("%02X ", encode[i]);}printf("\n");// 调整 asmhex 的大小asmhex.resize(asmhex.size() + size);  // 调整 asmhex 的大小memcpy_s(asmhex.data() + asmhex.size() - size, size, encode, size);  // 复制数据到 asmhex*OutSize = size;}else {printf("No machine code generated for '%s'\n", assembly);}// Clean up resourcesks_free(encode);ks_close(ks);return status;
}QByteArray QQSG::assembleCode(const QByteArray& asmcode) {int all_size = 0;bool hasErrors = false;QString text = QString::fromUtf8(asmcode);printf("Original assembly code: %s\n", text.toLocal8Bit().constData());QStringList lines = text.split('\n');for (QString& asmstr : lines) {asmstr = asmstr.trimmed();printf("Processing assembly code: %s\n", asmstr.toLocal8Bit().constData());if (asmstr.isEmpty())continue;size_t hex_size = 0;// 调用 AsmToHex 并获取结果int status = this->AsmToHex(KS_ARCH_X86, KS_MODE_32, asmstr.toLocal8Bit().data(), 0, m_hexstr, &hex_size);printf("Assembly conversion result: %s\n", asmstr.toLocal8Bit().constData());if (status != 0) {printf("Assembly conversion failed: %s\n", asmstr.toLocal8Bit().constData());m_hexstr.append(" <= instruction format error!");hasErrors = true;}else {all_size += hex_size;}}// If errors occurred, return an empty QByteArrayif (hasErrors) {printf("Errors occurred, returning an empty QByteArray\n");return QByteArray();}// Add a ret instruction at the end/*   asmhex.push_back(0xC3);*/all_size++;// 转换为 QByteArray 并返回QByteArray machineCode = QByteArray::fromRawData(reinterpret_cast<const char*>(asmhex.data()), asmhex.size());// 打印最终的机器码用于调试printf("Final machine code: %s\n", machineCode.toHex().constData());asmhex.clear();return machineCode;
}
void QQSG::on_pushButtonCodeInject_clicked()
{if (ui.lineEditCodeHwnd->text().isEmpty()) {QMessageBox::warning(this, tr("Warning"), tr("请输入目标窗口句柄!"));return;}// 尝试将文本转换为DWORD类型QString asmcode = ui.textEditShellCode->toPlainText();if (asmcode.isEmpty()) {QMessageBox::warning(this, tr("Warning"), tr("请输入汇编代码!"));return;}QString CodeHwndStr = "CodeHwnd:" + ui.lineEditCodeHwnd->text();for (int i = 0; i < m_clinetList.size(); ++i){QTcpSocket* socket = m_clinetList.at(i);if (socket->state() == QTcpSocket::ConnectedState) {socket->write(CodeHwndStr.toUtf8());}}
}
void QQSG::recevieReadyRead()
{for (int i = 0; i < m_clinetList.size(); i++){QTcpSocket* socket = m_clinetList.at(i);QByteArray data = socket->readAll()if (data.contains("StartShellcodeRemoteThread")){QString asmcode = ui.textEditShellCode->toPlainText();QByteArray asmcodeBytes = asmcode.toUtf8();QByteArray machineCode = QQSG::assembleCode(asmcodeBytes);DWORD processId = 0;QString text = ui.tableWidget->item(0, UITYPE::WINWND)->text();bool ok;int m_hWnd = text.toInt(&ok);GetWindowThreadProcessId((HWND)m_hWnd, &processId);HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);if (hProcess == NULL) {qDebug() << "Failed to open process:" << GetLastError();return;}PVOID pLibRemote = VirtualAllocEx(hProcess, NULL, machineCode.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);if (pLibRemote == NULL) {qDebug() << "Failed to allocate memory in remote process:" << GetLastError();CloseHandle(hProcess);return;}SIZE_T bytesWritten;BOOL result = WriteProcessMemory(hProcess, pLibRemote, machineCode.data(), machineCode.size(), &bytesWritten);if (!result || bytesWritten != machineCode.size()) {qDebug() << "Failed to write memory to remote process:" << GetLastError();VirtualFreeEx(hProcess, pLibRemote, 0, MEM_RELEASE);CloseHandle(hProcess);return;}HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLibRemote, NULL, 0, NULL);if (hThread == NULL) {qDebug() << "Failed to create remote thread:" << GetLastError();VirtualFreeEx(hProcess, pLibRemote, 0, MEM_RELEASE);CloseHandle(hProcess);return;}QMessageBox::warning(this, tr("Warning"), tr("请输入汇编代码!"));DWORD result = WaitForSingleObject(hThread, INFINITE);if (result != WAIT_OBJECT_0) {qDebug() << "Failed to wait for remote thread:" << GetLastError();VirtualFreeEx(hProcess, pLibRemote, 0, MEM_RELEASE);CloseHandle(hThread);CloseHandle(hProcess);return;}VirtualFreeEx(hProcess, pLibRemote, 0, MEM_RELEASE);CloseHandle(hThread);CloseHandle(hProcess);return; }   }
}

问题来了 在学习过程中,假如我想调用这个call 实现远线程,我写了 汇编语言:

//esi的值 是选中对象的相关参数 我们假设他是 0x12345678,

mov esi,0x12345678
mov ecx,0x138FB90
mov     ecx,[ecx]
push    esi
call   0xA26FB0
mov     ecx, eax
call    0x53D1D0

注入之后的结果如下:

Original assembly code: mov esi,0x12345678
mov ecx,0x138FB90
mov     ecx,[ecx]
push    esi
call   0xA26FB0
mov     ecx, eax
call    0x53D1D0
Processing assembly code: mov ecx,0x138FB90
Generated machine code: B9 90 FB 38 01
Assembly conversion result: mov ecx,0x138FB90
Processing assembly code: mov ecx,[ecx]
Generated machine code: 8B 09
Assembly conversion result: mov ecx,[ecx]
Processing assembly code: push esi
Generated machine code: 56
Assembly conversion result: push esi
Processing assembly code: call 0xA26FB0
Generated machine code: E8 AB 6F A2 00
Assembly conversion result: call 0xA26FB0
Processing assembly code: mov ecx,eax
Generated machine code: 89 C1
Assembly conversion result: mov ecx,eax
Processing assembly code: call 0x53D1D0
Generated machine code: E8 CB D1 53 00
Assembly conversion result: call 0x53D1D0
Processing assembly code: ret
Generated machine code: C3
Assembly conversion result: ret
Processing assembly code:
Final machine code: b990fb38018b0956e8ab6fa20089c1e8cbd15300c3
Received machineCode code: B9 90 FB 38 01 8B 09 56 E8 AB 6F A2 00 89 C1 E8 CB D1 53 00 
Received machineCode: B9 90 FB 38 01 8B 09 56 E8 AB 6F A2 00 89 C1 E8 CB D1 53 00 // 原代码中的机器码(由于语言规范及传入数据,开头的机器码不同我可以理解,call后为什么不相同呢)
8B 0D 90 FB 38 01 56 E8 B9 C1 4A 00 8B C8 E8 D2 23 FC FF
此时:线程注入没有反应;
问题:
1.为什么 call 0xA26FB0 与 call 0x53D1D0翻译后的机器码 与 源代码中(文章开头)中的机器码不同呢
2.解释这种现象的原因,是因为call 后的 是偏移量?
3.为什么 注入后没有反应;
4. 综合上述问题 ,我需要如何修改 才能实现远线程注入
5.为什么我学习别人的文章,代码里也没有相关的处理 却可以调用成功;
6.为什么内联汇编却可以呢 ,比如下面:当然 内联汇编 需要修改一下,不能直接传值DWORD 功能相关地址 =0x138FB90DWORD 选中目标 = 0x12345678;
DWORD call_1 =0xA26FB0;
DWORD call_2 =0xA26FB0;
_asm
{
mov esi,选中目标
mov ecx,功能相关地址
mov     ecx,[ecx]
push    esi
call   call_1 
mov     ecx, eax
call    call_2
}

解决方案

  如下是上述问题的解决方案,仅供参考:

  在你的问题中,你涉及到了远程线程注入和汇编代码的转换,特别是关于如何将汇编语言代码注入到远程进程中并使其执行。你遇到的主要问题是关于机器码转换的准确性以及在远程线程注入后代码没有执行的原因。让我们逐一解答这些问题。

问题分析与解答

  1. 为什么 call 0xA26FB0call 0x53D1D0 翻译后的机器码与源代码中的机器码不同?

    汇编中的 call 指令需要使用相对于当前指令的偏移量,而不是绝对地址。因此,翻译成机器码时,call 指令后的地址是一个相对地址。

    • 在你的代码中,call 0xA26FB0call 0x53D1D0 在实际生成机器码时,需要计算这些地址相对于 call 指令本身的偏移量。
    • 原始机器码中的 call 指令实际上包含的是偏移量,不是绝对地址。比如,E8 AB 6F A2 00 表示 call 指令的偏移量是 0x00A26FAB(相对于 call 指令的地址)。

    在你的机器码生成中,call 后的地址可能是基于某个假设的位置计算的偏移量,而不是实际的绝对地址。确保你的汇编器或代码生成工具计算了正确的相对地址偏移量。

  2. 解释这种现象的原因,是因为 call 后的地址是偏移量?

    是的,call 指令使用的是相对偏移量,而不是绝对地址。call 指令后面跟的是相对于下一条指令的偏移量(即 call 指令的地址加上偏移量等于目标地址)。

    如果你将绝对地址直接放到 call 指令中,生成的机器码可能不会正确地跳转到目标地址,因为它们需要使用相对地址计算。

  3. 为什么注入后没有反应?

    可能有以下原因:

    • 偏移量计算错误:如前所述,call 指令需要相对地址。请确保你计算了正确的偏移量,并将其应用于机器码生成中。
    • 权限问题:检查注入的代码是否具有足够的权限执行,确保目标进程允许代码注入和执行。
    • 内存保护:确保分配的内存具有正确的保护属性(如 PAGE_EXECUTE_READWRITE)。
  4. 如何修改才能实现远程线程注入?

    你需要确保以下几点:

    • 计算相对地址:在生成机器码时,计算 call 指令的相对偏移量。你可以在汇编阶段计算 call 指令的偏移量,然后再将其转化为机器码。
    • 确保内存权限:分配的内存区域需要有正确的权限设置,确保可以执行写入的机器码。
    • 验证注入:确保远程线程的创建和代码注入过程无误。可以通过调试工具检查注入的机器码是否正确执行。
  5. 为什么我学习别人的文章,代码里也没有相关的处理却可以调用成功?

    可能是因为这些文章使用了不同的技术栈或工具,这些工具自动处理了相对地址的计算。例如,有些框架或库可能在注入代码前已经计算并调整了相对地址。你可以参考这些工具或库的文档,了解它们如何处理地址计算。

  6. 为什么内联汇编却可以?

    内联汇编通常会由编译器处理,并且编译器会自动管理相对地址和跳转目标的计算。编译器在生成目标代码时会将 call 指令的相对地址计算得很准确,因此你不需要手动处理这些偏移量。

总结

要解决你面临的问题,你需要:

  • 确保在汇编到机器码的过程中计算正确的相对地址。
  • 检查内存分配和权限设置是否正确。
  • 使用调试工具验证注入后的机器码是否按预期执行。

在生成机器码时,特别是涉及 call 指令时,确保理解相对地址和绝对地址的区别,以及如何正确计算和插入相对偏移量。

  希望如上措施及解决方案能够帮到有需要的你。

  PS:如若遇到采纳如下方案还是未解决的同学,希望不要抱怨&&急躁,毕竟影响因素众多,我写出来也是希望能够尽最大努力帮助到同类似问题的小伙伴,即把你未解决或者产生新Bug黏贴在评论区,我们大家一起来努力,一起帮你看看,可以不咯。

  若有对当前Bug有与如下提供的方法不一致,有个不情之请,希望你能把你的新思路或新方法分享到评论区,一起学习,目的就是帮助更多所需要的同学,正所谓「赠人玫瑰,手留余香」。

☀️写在最后

  如上问题有的来自我自身项目开发,有的收集网站,有的来自读者…如有侵权,立马删除。再者,针对此专栏中部分问题及其问题的解答思路或步骤等,存在少部分搜集于全网社区及人工智能问答等渠道,若最后实在是没能帮助到你,还望见谅!并非所有的解答都能解决每个人的问题,在此希望屏幕前的你能够给予宝贵的理解,而不是立刻指责或者抱怨!如果你有更优解,那建议你出教程写方案,一同学习!共同进步。

  ok,以上就是我这期的Bug修复内容啦,如果还想查找更多解决方案,你可以看看我专门收集Bug及提供解决方案的专栏《CSDN问答解惑-专业版》,都是实战中碰到的Bug,希望对你有所帮助。到此,咱们下期拜拜。

码字不易,如果这篇文章对你有所帮助,帮忙给 bug菌 来个一键三连(关注、点赞、收藏) ,您的支持就是我坚持写作分享知识点传播技术的最大动力。

同时也推荐大家关注我的硬核公众号:「猿圈奇妙屋」 ;以第一手学习bug菌的首发干货,不仅能学习更多技术硬货,还可白嫖最新BAT大厂面试真题、4000G Pdf技术书籍、万份简历/PPT模板、技术文章Markdown文档等海量资料,你想要的我都有!

📣关于我

我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云2023年度十佳博主,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿哇。


相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Python实现图形学光栅化的Bresenham算法
  • Linux通过yum安装Docker
  • C高级day4
  • VulnHub-Bilu_b0x靶机笔记
  • 《在华为交换机上配置防止 ARP 攻击》
  • 对商品分类系统的若干问题的思考
  • python编程,把所有子目录和文件输出到文本文件
  • 基于JAVA+SpringBoot+Vue的线上辅导班系统的开发与设计
  • 基于CNN的10种物体识别项目
  • 2.《DevOps》系列K8S部署CICD流水线之部署NFS网络存储与K8S创建StorageClass
  • [leetcode刷题]面试经典150题之6轮转数字(简单)
  • 【C++篇】走进C++标准模板库:STL的奥秘与编程效率提升之道
  • python:编写一个函数查找字符串中的最长公共前缀
  • Python: networkx绘图
  • python基础题练习
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • 2019年如何成为全栈工程师?
  • canvas 五子棋游戏
  • echarts花样作死的坑
  • es6要点
  • IOS评论框不贴底(ios12新bug)
  • Java教程_软件开发基础
  • Java应用性能调优
  • js写一个简单的选项卡
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • python大佬养成计划----difflib模块
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • Vue官网教程学习过程中值得记录的一些事情
  • 工作中总结前端开发流程--vue项目
  • 理解在java “”i=i++;”所发生的事情
  • 你真的知道 == 和 equals 的区别吗?
  • 三分钟教你同步 Visual Studio Code 设置
  • 携程小程序初体验
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​iOS实时查看App运行日志
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • ‌分布式计算技术与复杂算法优化:‌现代数据处理的基石
  • $$$$GB2312-80区位编码表$$$$
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (一)搭建springboot+vue前后端分离项目--前端vue搭建
  • (转)Mysql的优化设置
  • (转)Oracle存储过程编写经验和优化措施
  • *算法训练(leetcode)第四十七天 | 并查集理论基础、107. 寻找存在的路径
  • .Net - 类的介绍
  • .NET CF命令行调试器MDbg入门(一)
  • .NET CORE Aws S3 使用
  • .NET Core 版本不支持的问题
  • .NET Core中如何集成RabbitMQ
  • .net framework4与其client profile版本的区别
  • .Net Web项目创建比较不错的参考文章