在 C# 程序中注入恶意 DLL

为什么 Windbg 附加到 C# 程序后,程序就处于中断状态了?它到底是如何实现的?其实简而言之就是线程的远程注入,这一篇就展开说一下。

实现原理

1. 基本思路
WinDbg 在附加进程的时候,会注入一个线程到 C# 进程 中,注入成功后,会执行一个 DbgBreakPoint() 函数,其实就是 int 3 ,这时候 CPU 就会执行 3 号中断函数,将当前进程的所有线程进行暂停,文字不好理解的话,画一个图大概就是这样。

 2. 案例演示
首先写一个简单的 C# 程序,不断的输出时间和标号,代码如下:

internal class Program
   {
       static void Main(string[] args)
       {
           for (int i = 0; i < 10000; i++)
           {
               Console.WriteLine($"{DateTime.Now},i={i}");
               Thread.Sleep(1000);
           }
       }
   }

把程序跑起来后,使用 WinDbg 附加,你可以发现 Command 自动切换到了 8 号线程,通过 k 命令可以看到最上面是一个 int 3 中断,截图如下:

 这里就有一个想法了,既然 WinDbg 可以注入,为何我的程序就注入不得呢?既然我的程序可以注入,那就可以做一些我想做的事情。

3. 自定义注入

有了自定义注入的想法,接下来的实现步骤大概是这样的。

  • 注入一个线程到 C# 程序中。
  • 让程序加载一个 dll 文件。
  • 在 dll 中做一些我想做的业务逻辑。

接下来新建一个 C++ 的动态链接库,在 [color=var(--weui-LINK)][url=]DLLMain[/url] 入口函数的  DLL_PROCESS_ATTACH 事件中写一个 printf 函数,如果在 C# 程序中输出来了,就算成功注入了,参考代码如下:

#include <Windows.h>
#include <stdio.h>
 
BOOL APIENTRY DllMain(HMODULE hModule,
 DWORD  ul_reason_for_call,
 LPVOID lpReserved
)
{
 switch (ul_reason_for_call)
 {
 case DLL_PROCESS_ATTACH:
  printf(" 总部,总部,我已经成功打入内部!ul_reason_for_call=%d\n ", ul_reason_for_call);
  break;
 }
 return TRUE;
}

要被加载的 MyInject.dll 已经构建完毕,接下来就用 Win32 API 的 CreateRemoteThread() 实现远程注入,但注入之前需要做三件事情。

  • 获取 C# 程序的 进程[color=var(--weui-LINK)][url=]句柄[/url]。
  • 在 C# 进程中申请一块内存空间,存放加载的 path 路径。
  • 调用 LoadLibraryW 函数在 C# 进程中实现 dll 加载。

过程有了,新建一个 C++ 控制台程序 ConsoleApplication1.exe, 整体的参考代码如下:

#include <iostream>
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <Tlhelp32.h>
 
DWORD GetPid(const WCHAR* szName)
{
 HANDLE hprocessSnap = NULL;
 
 PROCESSENTRY32 pe32 = { 0 };
 
 hprocessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 
 pe32.dwSize = sizeof(PROCESSENTRY32);
 
 if (Process32First(hprocessSnap, &pe32))
 {
  do {
   if (!wcscmp(szName, pe32.szExeFile)) {
    return (int)pe32.th32ProcessID;
   }
  } while (Process32Next(hprocessSnap, &pe32));
 }
 else
 {
  CloseHandle(hprocessSnap);
 }
 return 0;
}
 
int main()
{
 const wchar_t* path = L"D:\\net6\\ConsoleApp1\\x64\\Debug\\MyInject.dll"; //要注入的dll文件地址
 
 //1. 获取进程ID
 DWORD  procID = GetPid(L"ConsoleApp4.exe");
 
 //2. 获取进程句柄
 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procID);
 
 //3. 在目标进程中开辟一块空间
 LPVOID pRemoteAdress = VirtualAllocEx(hProcess, NULL, wcslen(path) * 2, MEM_COMMIT, PAGE_READWRITE);
 
 //4. 将 path 写入到这块空间中
 BOOL bRet = WriteProcessMemory(hProcess, pRemoteAdress, path, wcslen(path) * 2, NULL);
 
 //5. 让目标线程调用 LoadLibraryW 加载我们注入的 dll
 HMODULE hModule = GetModuleHandle(L"kernel32.dll");
 LPTHREAD_START_ROUTINE dwLoadAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryW");
 HANDLE hThread = CreateRemoteThread(
  hProcess,
  NULL,
  0,
  (LPTHREAD_START_ROUTINE)dwLoadAddr,
  pRemoteAdress,
  NULL,
  NULL
 );
 
 //6. 函数执行完后,释放这块空间。
 WaitForSingleObject(hThread, -1);
 VirtualFreeEx(hProcess, pRemoteAdress, 1, MEM_DECOMMIT);
 
 system("pause");
 return 0;
}

万事具备,接下来我们将 ConsoleApplication1.exe 启动,可以成功观察到 ConsoleApp4.exe 上已经注入成功的输出,截图如下:

这就是对 WinDbg 实现注入拦截的一个衍生知识,整体思路还是很明朗的,当然有注入,就有反注入,比如下面两条策略。

  • 设置进程的保护属性。
  • 屏蔽 或者 混淆 Win32 的 LoadLibraryW 函数。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

盘点60个Python各行各业管理系统源码Python爱好者不容错过

盘点60个Python各行各业管理系统源码Python爱好者不容错过 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 源码下载链接&#xff1a;https://pan.baidu.com/s/1VdAFp4P0mtWmsA158oC-aA?pwd8888 提取码&#xff1a;8888 项目名…

原来机械硬盘比内存慢10万倍

我们都知道机械硬盘的速度很慢&#xff0c;内存的速度很快&#xff0c;那么不同存储器之间的差距到底有多大呢&#xff1f; 我们先来看一幅图&#xff1a; CPU访问寄存器的时间是0.3纳秒&#xff0c;访问L1高速缓存的时间是1纳秒&#xff0c;访问L2高速缓存的时间是4纳秒… 秒…

Cmake学习

cmake大致 cmake_minimum_required(VERSION 3.0)project(test) #通过set自定义变量&#xff0c;通过${}取出 #set(SRC add.cpp main.cpp muti.cpp sub.cpp) #cmake搜索文件 宏定义PROJECT_SOURCE_DIR aux_source_directory(${PROJECT_SOURCE_DIR} SRC) #file(GLOB/GLOB_RECURSE…

Linux文件权限

R 代表可读 W 代表可写 X 代表可执行 文档类型有如下表示方法&#xff1a;   d - 目录&#xff0c;例如上表档名为『.gconf』的那一行&#xff1b; - - 文档&#xff0c;例如上表档名为『install.log』那一行&#xff1b; l - 链接档(link file)&#xff1b; b …

带你快速掌握Linux最常用的命令(图文详解)- 最新版(面试笔试常考)

最常用的Linux指令&#xff08;图文详解&#xff09;- 最新版 ls&#xff1a;列出目录中的文件和子目录。&#xff08;重点&#xff09;cd&#xff1a;改变当前工作目录。绝对路径&#xff1a;相对路径 pwd&#xff1a;显示当前工作目录的路径。mkdir&#xff1a;创建一个新的目…

[Kettle] 字段处理

1.增加常量 常量是指在计算机程序运行过程中其值不能改变的量 常量可以是任何的数据类型&#xff0c;例如&#xff0c;圆周率"3.141159"、中国首都"北京"等都可以是常量 增加常量是指在数据中增加一个字段&#xff0c;并给字段设置一个固定的值 数据源…

java源码-工程讲解

1、 工程目录 源码工程目录讲解部分&#xff0c;讲解过程会让大家对后端源码工程有一个大致的了解&#xff0c;能让大家在此改造&#xff0c;就可以衍生出一些新的功能&#xff0c;需要对java技术深入了解&#xff0c;需要看后续java技术讲解部分 整个架构是一个spring-boot…

​软考-高级-系统架构设计师教程(清华第2版)【第16章 嵌入式系统架构设计理论与实践(P555~613)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第16章 嵌入式系统架构设计理论与实践&#xff08;P555~613&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

Redis 9 数据库

4 设置键的生存时间或过期时间 通过EXPIRE命令或者PEXPIRE命令&#xff0c;客户端可以以秒或者毫秒精度为数据库中的某个键设置生存时间&#xff08;TimeToLive&#xff0c;TTL&#xff09;&#xff0c;在经过指定的秒数或者毫秒数之后&#xff0c;服务器就会自动删除生存时间…

Python的数据分析包Pandas?示例文章完成版来啦~

文章目录 前言一、Pandas简介二、Python Pandas的使用 总结 前言 pandas 是基于NumPy 的一种工具&#xff0c;该工具是为了解决数据分析任务而创建的。 Pandas 是python的一个数据分析包&#xff0c;最初由AQR Capital Management于2008年4月开发&#xff0c;并于2009年底开源…

【机器学习Python实战】logistic回归

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习python实战 欢迎订阅&#xff01;后面的内容会越来越有意思~ ⭐内容说明&#xff1a;本专栏主要针对机器学习专栏的基础内容进行python的实现&#xff0c;部分…

机器学习第8天:SVM分类

文章目录 机器学习专栏 介绍 特征缩放 示例代码 硬间隔与软间隔分类 主要代码 代码解释 非线性SVM分类 结语 机器学习专栏 机器学习_Nowl的博客-CSDN博客 介绍 作用&#xff1a;判别种类 原理&#xff1a;找出一个决策边界&#xff0c;判断数据所处区域来识别种类 简单…

Consistency Models 阅读笔记

Diffusion models需要多步迭代采样才能生成一张图片&#xff0c;这导致生成速度很慢。Consistency models的提出是为了加速生成过程。 Consistency models可以直接一步采样就生成图片&#xff0c;但是也允许进行多步采样来提高生成的质量。 Consistency models可以从预训练的扩…

单元测试实战(四)MyBatis-Plus 的测试

为鼓励单元测试&#xff0c;特分门别类示例各种组件的测试代码并进行解说&#xff0c;供开发人员参考。 本文中的测试均基于JUnit5。 单元测试实战&#xff08;一&#xff09;Controller 的测试 单元测试实战&#xff08;二&#xff09;Service 的测试 单元测试实战&am…

【电路笔记】-最大功率传输

最大功率传输 文章目录 最大功率传输1、概述2、最大功率传输定理 (MPTT)3、示例4、阻抗匹配5、总结 当工程师设计电子电路时&#xff0c;他们会跟踪许多不同的参数&#xff0c;但最重要的参数之一是功率。 在现代电路中&#xff0c;功率在多个阶段中不断变化&#xff0c;有时由…

最常用的结构体初始化方式

结构体最常用的初始化方式就是用memset把这块区域清0 注意不能这么写 STU stu[5]; stu (STU*)malloc(sizeof(stu)); 数组名不允许被赋值&#xff0c;它只是个表达式

AI Navigation导航系统_unity基础开发教程

AI Navigation导航系统 安装插件烘焙导航系统障碍物创建人物的AI导航动态障碍物 在unity编辑器中&#xff0c;有一个灰常好用的插件&#xff1a;Navigation。有了它1&#xff0c;你就可以实现人物自动走到你鼠标点击的位置&#xff0c;而且还会自动避开障碍物&#xff0c;下面就…

微信小程序会议OA首页-开发说明创建项目关于flex布局关于尺寸单位(rpx)关于WXS轮播图会议信息

目录 1. 创建项目 2. 关于flex布局 3. 关于尺寸单位&#xff08;rpx&#xff09; 4. 关于WXS 4. 轮播图 5. 会议信息 1. 创建项目 基于微信原生开发工具&#xff0c;稳定版 Stable Build (1.06.22010310) 创建项目前&#xff0c;请确定有小程序测试账号 使用向导创建一个…

【Linux】进程间通信 -- 共享内存

共享内存 共享内存是SystemV标准进程间通信的一种&#xff0c;该标准还有消息队列和信号量&#xff0c;但下文主要介绍共享内存&#xff0c;然后在谈一下信号量的内容。SystemV标准的进程间通信可以看做单机版的进程间通信。 // 1. log.hpp #pragma once#include <iostrea…

网站优化工具Google Optimize

Google Optimize 是一款由Google提供的网站优化工具。Google Optimize旨在帮助网站管理员通过对网页内容、设计和布局进行测试和优化&#xff0c;来提升用户体验和网站的转化率。 Google Optimize 提供了 A/B 测试和多变量测试功能&#xff0c;使网站管理员能够比较和评估不同…