将代码注入其它进程的三种方法

C#外挂、钩子对第三方窗体进行操作、取值 HwndMain = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "主窗体名称", null);if (stringBuilder.ToString().Contains("子窗体名称"))HwndMain = FindWindow("主窗体名称", null);private void Example1()//查找窗体并写入值。private void Example2()//查找窗体并读取值。//获取子窗体里的控件。//执行窗体、控件查找并传值、取值。 阅读详情

在互连网络飞速发展的今天,网络的充分利用虽然方便了人们的生产和生活,但也随之带来了严重的网络安全问题。许多黑客可以利用各种操作系统或者应用软件的漏洞进入到一台联入互连网络的主机中,并且利用木马软件实现对该主机的长期控制。一些木马为了实现自身运行的隐蔽,往往会将自身代码注入到其它进程中来运行。有道是“知己知彼,百战不殆”,下面随本文的介绍来认识一下将代码注入其它进程的三种方法。

将代码注入其它进程,则意味着在另一个存在的进程地址空间中执行用户编写的代码。实现这一目标的方法通常有一下三种,即:

1、  将实现代码编写为DLL,然后通过Windows钩子来将DLL映射到另一进程中。

2、  将实现代码编写为DLL,然后通过CreateRemoteThread和LoadLibrary技术将DLL映射到另一进程中。

3、  利用WriteProcessMemory技术将代码直接拷贝到其它进程中,然后通过CreateRemoteThread函数来执行编写的代码。

下面逐一介绍上述三种方法的具体实现过程。

I、Windows 钩子技术

钩子是Windows的一个主要特性之一,它就主要认为是在系统中监视一些线程间的消息传输。Windows具有两种类型的钩子:

1、  局部钩子,用来监视所有往来于系统和本进程之间消息。

2、  远程钩子,它可以用于:

a、  Thread-specific,监视指定进程和其它线程间的消息。

b、  System-wide,坚持系统中当前运行的任何线程间传输的消息。

如果钩子线程从属于另一进程,则钩子程序必须编写为DLL,借着系统将包含钩子程序的DLL映射到钩子线程的地址空间中。此时Windows将映射整个DLL,而不仅仅是钩子程序,这就是为什么我们可以利用Windows钩子来实现将代码注入另一进程地址空间中的原因。

限于篇幅原因,本文将不会详细讨论关于钩子的更多细节(细节参见MSDN中有关SetWindowsHookEx API函数相关文档),仅介绍实现代码注入的关键细节。

1、当成功调用SetWindowsHookEx函数以后,系统将自动映射DLL到钩子线程的地址空间中,但映射不会马上起作用。这是因为,Windows钩子同样是基于消息机制的,因此,当一个适当事件Event发生以前,映射都不会起作用。比如,当安装一个用来监视某些线程的所有非队列消息时,DLL在收到一个真实的消息以前是不会被映射到其它进程中的。为了使映射立刻产生作用,则必须在成功调用了SetWindowsHookEx之后,再向钩子线程发送一个适当的事件。同样,如果调用UnhookWindowsHookEx来卸载钩子,也需要做同样的工作。

2、当安装了一个钩子以后,钩子可能会影响到整个系统中的所有消息事件,为了避免不必要的钩子功能,可以选择使用thread-specific钩子。比如下面这段代码:

BOOL APIENTRY DllMain ( HANDLE hModule , DWORD ul_reason_for_call , LPVOID lpReserved )

 

 

{

 

 

       if ( ul_reason_for_call == DLL_PROCESS_ATTACH )

 

 

       {

 

 

              char lib_name[MAX_PATH];

 

 

              ::GetModuleFileName ( hModule , lib_name , MAX_PATH );

 

 

              ::LoadLibrary ( lib_name );

 

 

 

 

 

              ::UnhookWindowsHookEx ( g_hHook );

 

 

       }

 

 

       return TRUE;

 

 

}

 

 

上述代码进行了如下的工作。首先,使用Windows钩子将DLL映射到了另一进程中,此时,DLL实际上已经完成了映射工作,一般来说,一旦第一个发往钩子的消息到达,DLL就将被解除映射。使用LoadLibrary正是为了避免映射的解除。那么,一旦完成了代码的执行工作,怎样卸载DLL呢?这时候,UnhookWindowsHookEx不会做任何事情,因为钩子线程已经被卸载了,因此,只能通过下面的来完成DLL的卸载。

 

在想要下载DLL以前,安装另一钩子;

 

发送一个指定的信息给另一进程(被注入代码的进程);

 

在钩子中捕捉这一消息,然后调用FreeLibrary和UnhookWindowsHookEx。

 

现在,已经可以使用DLL来实现将代码注入到其它进程中(或者从其它进程中卸载)。该方法适用于Win9x和WinNT操作系统。

 

II、CreateRemoteThread和LoadLibrary技术

一般来说,任何进程都可以通过使用LoadLibrary API函数来动态载入DLL。那么,自己编写的DLL怎么样才能使其它进程载入呢?也就是说,怎样才能强迫一个外部的进程去调用LoadLibrary函数呢?方法是,利用CreateRemoteThread。

 

先来认识一下LoadLibrary和FreeLibrary:

 

       HMODULE LoadLibrary(

 

 

             LPCTSTR lpFileName   // file name of module

 

 

       );

 

 

       BOOL FreeLibrary(

 

 

             HMODULE hModule   // handle to DLL module

 

 

       );

 

 

将上述两个函数与ThreadProc(CreateRemoteThread创建的线程入口函数)的声明做比较:

DWORD WINAPI ThreadProc(

              LPVOID lpParameter   // thread data

 

);

 

通过比较可以看出,所有函数都使用同样的调用方式,且都接受32位的参数。返回值的尺寸大小也相同。这表明,可以传送一个指针给LoadLibrary(FreeLibrary)来作为CreateRemoteThread构造的线程线程序。

再来看CreateRemoteThread的定义:

HANDLE CreateRemoteThread(

 

        HANDLE hProcess,                          // handle to process

 

              LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD

 

               DWORD dwStackSize,                        // initial stack size

 

              LPTHREAD_START_ROUTINE lpStartAddress,    // thread function

 

              LPVOID lpParameter,                       // thread argument

 

              DWORD dwCreationFlags,                    // creation option

 

              LPDWORD lpThreadId                        // thread identifier

 

);

 

从中可以发现两个问题,首先,lpStartAddress参数必须是在远程进程中线程程序的开始地址。其次,如果lpParameter参数作为普通的32-bit值传送给ThreadProc,当然没有任何问题,但如果参数lpParameter作为一个指针比如char字符串进行传送的话,则该参数一定指向了在远程进程中的一些数据。

对于上述两个问题,第一个实际上系统已经帮助我们解决了。这是因为,LoadLibrary和FreeLibrary函数都是系统Kernel32.dll中的函数,对于任何一个“Normal”级的进程来说,Kernel32.dll确保了他们使用相同的地址。每一个进程中的LoadLibrary和FreeLibray也一样。这就保证了传递给远程进程的指针是有效的。

对于第二个问题,可以使用WriteProcessMemory函数来拷贝DLL模块名称来解决。

下面介绍使用CreateRemoteThread和LoadLibrary的具体实现步骤。

1、  获取远程进程的HANDLE句柄(OpenProcess)。

2、  在远程进程中为DLL名称分配内存空间(VirtualAllocEx)。

3、  写入DLL名称,包括完整路径,到以分配的存储空间中(WriteProcessMemory)。

4、  通过CreateRemoteThread和LoadLibrary映射DLL到远程进程中。

5、  等待远程线程终止(WaitForSingleObject),直到LoadLibrary调用返回。

6、  返回远程线程的退出代码(GetExitCodeThread),注意这个值已经由LoadLibrary返回了,它是映射DLL的基址HMODULE。

7、  释放第2步中申请的内存(VirtualFreeEx)。

8、  使用CreateRemoteThread和FreeLibrary将DLL从远程进程中卸载。这里会用到步骤6中HMODULE,它将会作为参数lpParameter的值传递给CreateRemoteThread。

9、  等待直到线程终止(WaitForSingleObject)。

本文给出下面的代码片段,以说明具体的实现方法。

HANDLE hThread;

 

 

char

    szLibPath[_MAX_PATH];  // The name of our "LibSpy.dll" module

 

                              

// (including full path!);

 

void

*   pLibRemote;   // The address (in the remote process) where

 

                     

// szLibPath will be copied to;

 

DWORD   hLibModule;  

// Base address of loaded module (==HMODULE);

 

HMODULE hKernel32 = ::GetModuleHandle("Kernel32");

 

 

 

 

 

// initialize szLibPath

 

//...

 

 

 

 

// 1. Allocate memory in the remote process for szLibPath

 

// 2. Write szLibPath to the allocated memory

 

pLibRemote = ::VirtualAllocEx( hProcess, NULL, sizeof(szLibPath),

 

 

                               MEM_COMMIT, PAGE_READWRITE );

 

 

::WriteProcessMemory( hProcess, pLibRemote, (void*)szLibPath,

 

 

                      sizeof(szLibPath), NULL );

 

 

 

 

 

 

 

 

// Load "LibSpy.dll" into the remote process

 

// (via CreateRemoteThread & LoadLibrary)

 

hThread = ::CreateRemoteThread( hProcess, NULL, 0,

 

 

            (LPTHREAD_START_ROUTINE) ::GetProcAddress( hKernel32,

 

 

                                       "LoadLibraryA" ),

 

 

             pLibRemote, 0, NULL );

 

 

::WaitForSingleObject( hThread, INFINITE );

 

 

 

 

 

// Get handle of the loaded module

 

::GetExitCodeThread( hThread, &hLibModule );

 

 

 

 

 

// Clean up

 

::CloseHandle( hThread );

 

 

::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );

 

 

//(代码完毕)

 

 

 

 

 

此时,代码实际上已经注入到了远程进程中。这些代码存在于DllMain中,且已经被执行。这时,可以通过下面的代码将Dll从目标进程中卸载。

 

 

 

 

// Unload "LibSpy.dll" from the target process

// (via CreateRemoteThread & FreeLibrary)

hThread = ::CreateRemoteThread( hProcess, NULL, 0,

            (LPTHREAD_START_ROUTINE) ::GetProcAddress( hKernel32,

                                       "FreeLibrary" ),

            (void*)hLibModule, 0, NULL );

::WaitForSingleObject( hThread, INFINITE );

 

 

 

 

// Clean up

::CloseHandle( hThread );

 

 

 

III、CreateRemoteThread和WriteProcessMemory技术

第三种方法的基本思想是拷贝一些代码到另一进程的地址空间中然后执行。这种方法代替了编写独立的DLL,而是直接将代码使用WriteProcessMemory API函数拷贝到远程进程中。然后通过CreateRemoteThread来执行它。

 

本文前面已经介绍过CreateRemoteThread的函数原型,注意以下几点:

 

1、              hProcess参数是CreateRemoteThread的附加参数,它是进程决定创建哪个线程的句柄。

 

2、              lpStartAddress参数是线程在远程进程地址空间中的开始地址。它必须存在于远程进程中,因此不能简单的拷贝一个地址句柄传递给本地的ThreadFunc,而必须先将代码拷贝到远程进程中。

 

3、              对于lpParameter参数也一样,也必须将他拷贝到远程进程中。

 

下面概括一下使用CreateRemoteThread和WriteProcessMemory的具体步骤。

 

1、 返回远程进程的句柄HANDLE(OpenProcess)

 

2、 在远程进程的地址空间中为待注入的代码分配内存(VirtualAllocEX)

 

3、 将已初始化后的INJDATA结构的一个拷贝写入分配的内存(WriteProcessMemory)

 

4、 在远程进程的地址空间中为注入的代码分配内存

 

5、 将ThreadPunc的一个拷贝写入分配的内存

 

6、 使用CreateRemoteThread来执行远程的ThreadFunc拷贝

 

7、 等待远程线程的终止(WaitForSingleObject)

 

8、 从远程进程中返回执行结果(ReadProcessMemory或GetExitCodeThread)

 

9、 释放已申请的内存,包括步骤2和步骤4中的申请(VirtualFreeEx)

 

10、             关闭返回的句柄,包括步骤1和步骤6中的HANDLE(CloseHandle)

 

上述步骤中需要定义INJDATA结构:

 

typedef struct {

 

 

       HWND    hwnd;

 

 

       SENDMESSAGE         fnSendMessage;  // pointer to user32!SendMessage

 

 

 

 

 

       BYTE     pbText[128 * sizeof(TCHAR)];

 

 

} INJDATA, *PINJDATA;

 

 

构造ThreadFunc时将INJDATA作为传递的参数:

 

static DWORD WINAPI ThreadFunc (INJDATA *pData)

 

 

{

 

 

       return 0;

 

 

}

 

 

这样,就可以在ThreadFunc中加入一些想做的事情,并且注入到其它进程中来执行。

C#写Hook(SetWindowsHookEx、UnHookWindowsHookEx)使用示例 钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。 钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。 运行 阅读详情

相关推荐

SharpNeedle:将C#代码注入正在运行的进程

夏普针 一个将C#dll正确注入其他进程的项目。 注意:SharpNeedle当前仅支持32位进程。 欢迎您创建添加64位支持的请求请求。 基本原理 虽然仅将注入的自定义dll加载到目标进程的内存空间中很有趣,但这仅是故事的一半。 大多数dll注入教程将在上半部分详细介绍,但随后您将不得不从DllMain中运行代码,这是一个危险且有限的命题。 有关为什么应避免在DllMain中执行任何有趣操作的更多信息,请阅读Raymond Chen的。 该项目旨在改变缺乏良好的dll注入信息的情况,提供一种开源方法,不仅可以注入dll,还可以遍历导出地址表并在dll上调用方法。 该项目专门针对将托管代

有关FreeLibrary的问题

1、我的调用程序接口 2、当我在执行FreeLibrary之前,内存是这样的 3、当执行FreeLibrary之后: 遇到这种无厘头的错误也是醉了,具体原因还不清楚,问题崩溃在Cstring的Release中 4、dll并没有改动,只是将CString mm的声明和赋值分开,然后就没事了 有图有真想 回头研究下CString ...

yuchu123456的博客 3232

银河麒麟V10离线升级OpenSSH实战:从编译到回滚全流程

OpenSSH作为Linux系统远程登录的核心组件,其版本升级直接关系到系统安全与等保合规。在信创环境下,银河麒麟V10自带的OpenSSH版本往往无法满足漏洞扫描与安全加固要求,而离线编译升级涉及依赖处理、编译参数、服务替换与回滚方案等多个技术环节。本文围绕银河麒麟V10(x86_64)平台,详细讲解OpenSSH离线升级的完整实操流程,包括环境摸底、依赖包安装、源码编译、配置文件兼容性处理、服务重启验证以及常见问题排查,并分享批量升级与安全加固的工程经验,帮助运维人员在不断网、不重装的前提下一次成功完成

weixin_30582943的博客 388

C#编程技巧之钩子函数的使用——SetWindowsHookEx

  本随笔较长,读者可直接到最地下下载示例程序。   总所周知:C#是.NET Framework平台的相伴语言,用它本身的类库和编译器提供的方法是无法实现全局钩子的。但实际上对于非托管代码的调用在C#中是成立的,使用DllImport属性可以引用非托管代码类库中的方法。钩子函数存在于user32.dll中,函数原型如下:   HHOOK WINAPI SetWindowsHookEx(  ...

weixin_34220179的博客 348

什么是论文的创新点?公式化描述算是创新点吗?

写科研论文时,挑战之一就是如何让你的工作“脱颖而出”,也就是要有创新性。不管实验多么精确、推导多么复杂,若没有真正的创新,论文很可能会被拒。关于如何创新问题上,我最近在看刘雪峰老师的《科技论文写作指南》,看到了很多关于写作的新论述,在这里和大家进行分享。

加百力 的技术博客 1926

LabView实战:精准实现float到十六进制的转换与高低位拆分

本文详细讲解了在LabVIEW中实现单精度浮点数(float)到十六进制字符串转换,并进行高低16位拆分的实战方法。针对工业通信中设备协议要求,核心使用强制类型转换(Type Cast)获取内存原始数据,避免数值转换错误,并提供了完整的VI构建步骤、交叉验证技巧及常见踩坑经验(如字节序、字符串格式),确保数据通信的准确性。

assembly8low的博客 1767

向其他进程注入代码的三种方法

  发表日期:2005年7月3日      作者:袁晓辉 译     【编辑录入:webmaster】  向其他进程注入代码的三种方法    本文章翻译自Robet Kuster的Three Ways to Inject Your Code into Another Process一文,原版地址见下面。本文章版权归原作者所有。   

turobber_tu的专栏 742

AVEVA PDMS 二次开发之PML实战:从宏到自定义窗体的效率提升

本文详细介绍了AVEVA PDMS二次开发中PML语言的应用,从基础宏编写到高级窗体开发,全面提升工程设计效率。通过实战案例展示如何利用PML实现批量操作、流程自动化和交互优化,帮助工程师快速掌握这一强大工具。

weixin_42549451的博客 341

[原创&译]向其他进程注入代码的三种方法

向其他进程注入代码的三种方法原版地址:http://www.codeproject.com/threads/winspy.asp?df=100&forumid=16291&select=1025152&msg=1025152下载整个压缩包下载WinSpy 作者:Robert Kuster翻译:袁晓辉(hyzs@sina.com)摘要:如何向其他线程的地址空间中注入代码并在这个线程的上下文中执行之。

farproc's blog 1万+

Ubuntu24.04下Librenms的完整安装与配置指南

本文提供了在Ubuntu 24.04 LTS系统上完整安装与配置LibreNMS网络监控系统的详细指南。内容涵盖系统环境准备、依赖安装、源码获取、PHP/数据库/Nginx配置、Composer安装、网页向导设置以及设备添加与日常使用,帮助用户快速部署一套功能强大的开源网络监控解决方案。

tgb3456789的博客 1139

PCB设计必看:铜皮厚度与载流能力对照表(附Excel计算工具)

本文深入解析了PCB设计中铜皮厚度与载流能力的核心关系,提供了基于IPC-2152标准的动态计算逻辑与实用Excel工具。文章不仅分享了载流对照表,更重点剖析了影响载流能力的关键因素(如铜厚、线宽、温升、布线层),并给出了高电流设计的实战技巧与测试验证方法,帮助工程师规避常见陷阱,实现从理论到实践的闭环设计。

weixin_29228781的博客 724

vc++ 向其他进程注入代码的三种方法

vc++ 向其他进程注入代码的三种方法 2008-11-21 07:32:31| 分类: C VC++ | 标签: |字号大中小 订阅 导言: 我们在Code project(www.codeproject.com)上可以找到许多密码间谍程

fysy0000的专栏 4535

claude使用教程

提供了三种模型:claude,codex, gemini,三种模型都共用同一个apikey, 有开发需求使用claude效果较好,知识问答等场景gemini效果会更好些,本文只提供了claude的安装方式,剩下两种按需按照以下参考链接安装下即可,安装有问题参考文档:https://www.aicodemirror.com/dashboard/official-installation/macos-linux (不需要挂梯子,自己手机号注册就好)

lichao19871216的博客 3500

向其他进程注入代码的三种方法(injectdll)

向其他进程注入代码的三种方法(injectdll)

ffghggf的博客 3711

【传奇开心果系列】Flet框架实现的窗口屏幕居中示例自定义模板特色和实现原理深度分析

本文介绍了使用Flet框架实现窗口屏幕居中的方法。通过设置page.window.center()方法,程序会自动计算屏幕尺寸和窗口位置实现居中显示。文章建议将任务栏设为自动隐藏以获得更精确的居中效果,并详细分析了Flet窗口管理的实现原理,包括坐标计算、跨平台兼容性等技术细节。该方案提供了简洁的API调用,支持动态调整窗口位置和多显示器环境,源码可通过优快云下载。

jackchuanqi的博客 1201

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

vc++ 向其他进程注入代码的三种方法(转)

vc++ 向其他进程注入代码的三种方法(转) 2010年06月29日   vc++ 向其他进程注入代码的三种方法   导言:   我们在Code project上可以找到许多密码间谍程序(那些可以看到别的程序中密码框内容的软件),他们都依赖于Windows钩子技术。要实现这个还有其他的方法吗?有!但是,首先,让我们简单回顾一下我们要实现的目标,以便你能弄清楚我在说什么。   要读取...

jhq470hs 194

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

上一篇: 全局钩子DLL如何被挂接到其它进程地址空间中并正确映射函数
下一篇: C++实现CD抓轨转WAV
tomorrowsprogress
博客等级 码龄20年 16粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值