DLL注入

DLL注入指的是向运行中的其他进程强制插入特定的DLL文件。从技术细节来说,DLL注入命令其他进程自行调用LoadLibrary() API,加载(Loading)用户指定的DLL文件。DLL注入与一般DLL加载的区别在于,加载的目标进程是其自身或其他进程。下图描述了DLL注入的概念。

从图中可以看到,myhack.dll已被强制插入notepad进程(本来notepad并不会加载myhack.dll )。加载到notepad.exe进程中的myhack.dll与已经加载到notepad.exe进程中的DLL(kemel32.dll、user32.dll) —样,拥有访问notepad.exe进程内存的(正当的)权限,这样用户就可以做任何想做的事了(比如:向notepad添加通信功能以实现Messenger、文本网络浏览器等)。

DLL被加载到进程后会自动运行DllMain()函数,用户可以把想执行的代码放到DllMain()函数,每当加载DLL时,添加的代码就会自然而然得到执行。利用该特性可修复程序Bug,或向程序添加新功能。

DLL(Dynamic Linked Library,动态链接库)被加载到进程后会自动运行DllMain()函数,用户可以把想执行的代码放到DllMain()函数,每当加载DLL时,添加的代码就会自然而然得到执行。利用该特性可修复程序Bug,或向程序添加新功能。

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
switch( dwReason )
{
case DLL_PROCESS_ATTACH:
// 添加想执行的代码
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
} return TRUE;
}

DLL注入示例

使用LoadLibrary() API加载某个DLL时,该DLL中的DllMain()函数就会被调用执行。DLL注入的工作原理就是从外部促使目标进程调用LoadLibrary() API (与一般DLL加载相同),所以会强制调用执行DLL的DllMain()函数。并且,被注入的DLL拥有目标进程内存的访问权限,用户可以随意操作(修复Bug、添加功能等)。下面看一些使用DLL注入技术的示例。

改善功能与修复Bug

DLL注入技术可用于改善功能与修复Bug。没有程序对应的源码,或直接修改程序比较困难时,就可以使用DLL注入技术为程序添加新功能(类似于插件),或者修改有问题的代码、数据。

消息钩取

Windows OS默认提供的消息钩取功能应用的就是一种DLL注入技术。与常规的DLL注入唯一的区别是,OS会直接将已注册的钩取DLL注入目标进程。

我曾经从网上下载过一个Hex Editor,它不支持鼠标滚轮滑动,所以我用消息钩取技术为其添加了鼠标滚轮支持。虽然可以下载更多、更好用的Hex Editor,但是利用学到的技术改善、扩展程序功能是一种非常妙的体验。这样不仅能解决问题,还锻炼了 我们灵活应用技术的能力(此后我就开始对使用逆向技术改善已有程序的功能产生了浓厚兴趣)。

API 钩取

API钩取广泛应用于实际的项目开发,而进行API钩取时经常使用DLL注入技术。先创建好DLL形态的钩取函数,再将其轻松注入要钩取的目标进程,这样就完成了API钩取。这灵活运用了 “被注入的DLL拥有目标进程内存访问权限”这一特性。

其他应用程序

DLL注入技术也应用于监视、管理PC用户的应用程序。比如,用来阻止特定程序(像游戏、股票交易等)运行、禁止访问有害网站,以及监视PC的使用等。管理员(或者父母)主要安装这类拦截/阻断应用程序来管理/监视。受管理/监视的一方当然千方百计地想关闭这些监视程序,但由于这些监视程序采用DLL注入技术,它们可以隐藏在正常进程中运行,所以管理员一般不用担心被发现或被终止(若用户强制终止Windows系统进程,也会一并关闭系统,最后也算达成了拦截/阻断这一目标)。

恶意代码

恶意代码制作者们是不会置这么好的技术于不顾的,他们积极地把DLL注入技术运用到自己制作的恶意代码中。这些入把自己编写的恶意代码隐藏到正常进程(winlogon.exe、services.exe、svchost.exe、explorer.exe等),打开后门端口( Backdoor port ),尝试从外部连接,或通过键盘偷录(Keylogging)功能将用户的个入信息盗走。只有了解恶意代码制作者们使用的手法,才能拿出相应对策

DLL注入的实现方法

向某个进程注入DLL时主要使用以下三种方法:

  • 创建远程线程(CreateRemoteThread() API)
  • 使用注册表(AppInit_DLLs值)
  • 消息钩取(SetWindowsHookEx() API)

使用CreateRemoteThread()函数进行DLL注入

练习示例myhack.dll

本示例将把myhack.dl注入notepad.exe进程,被注入的myhack.dll功能是联网下载http://www.naver.com/index.html文件

首先打开32位notepad++.exe(必须是32位,否则实验不能出来index.html)



鉴于很难找到32位的notepad,下面贴个32位notepad++.exe下载地址

链接:https://pan.baidu.com/s/1ErLkLlJQ28gN2H_DBghq_w?pwd=fire

提取码:fire



和一个DLL文件(此DLL的作用是下载一个.html)以及将DLL注入进notepad的EXE文件:



首先我们打开notepad文件,利用process explorer查看notepad文件的PID:



打开管理员cmd(否则会报错,权限不够),在InjectDll.exe目录下,输入指令:InjectDll.exe 12440 C:\Users\Zer0\Desktop\bin\myhack.dll



cmd显示我们注册成功,然后我们在process explorer上查看dll是否被注入成功(如果用的是64位记事本,那么很有可能即使cmd出现success的情况,在process explorer中也找不到myhack.dll,同时目录也不会生成index.html),在View菜单中,选择Show Lower Pane与Lower Pane Views - DLLs项。就可以看到:



可以看到myhack.dll已经被成功加载进去了。然后我们打开dll注入成功后的index.html,查看url是否被成功下载。



出现这个页面就是DLL注入成功了!

分析示例源码

以下介绍的源代码是用Micosoft Visual C++ Express 2010编写的,在Windows XP/732位操作系统中通过测试。

Myhack.cpp

先分析一下myhack.dll源代码(myhack.cpp )。

#include "windows.h"
#include "tchar.h" #pragma comment(lib, "urlmon.lib") #define DEF_URL (L"http://www.naver.com/index.html")
#define DEF_FILE_NAME (L"index.html") HMODULE g_hMod = NULL; DWORD WINAPI ThreadProc(LPVOID lParam)
{
TCHAR szPath[_MAX_PATH] = {0,}; if( !GetModuleFileName( g_hMod, szPath, MAX_PATH ) )
return FALSE; TCHAR *p = _tcsrchr( szPath, '\\' );
if( !p )
return FALSE;
//下载指定网站的index.html
_tcscpy_s(p+1, _MAX_PATH, DEF_FILE_NAME); URLDownloadToFile(NULL, DEF_URL, szPath, 0, NULL); return 0;
} BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
HANDLE hThread = NULL; g_hMod = (HMODULE)hinstDLL; switch( fdwReason )
{
case DLL_PROCESS_ATTACH : //加载时
OutputDebugString(L"<myhack.dll> Injection!!!"); //输出调试字符串
hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); //创建线程
CloseHandle(hThread);
break;
} return TRUE;
}

在DllMain()函数中可以看到,该DLL被加载(DLL_PROCESS_ATTACH)时,先输出一个调试字符串(“myhack.dll Injection!!!”),然后创建线程调用函数(ThreadProc)。在ThreadProc()函数中通过调用urlmon!URLDownloadToFile() API来下载指定网站的index.html文件。前面提到过,向进程注入DLL后就会调用执行该DLL的DllMain()函数。所以当myhack.dll注入notepad.exe进程后,最终会调用执行URLDownloadToFile()API。

InjectDII.cpp

InjectDll.exe程序用来将myhack.dll注入notepad.exe进程,下面看一下其源代码。

#include "windows.h"
#include "tchar.h" BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid; if( !OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken) )
{
_tprintf(L"OpenProcessToken error: %u\n", GetLastError());
return FALSE;
} if( !LookupPrivilegeValue(NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid) ) // receives LUID of privilege
{
_tprintf(L"LookupPrivilegeValue error: %u\n", GetLastError() );
return FALSE;
} tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if( bEnablePrivilege )
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0; // Enable the privilege or disable all privileges.
if( !AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
_tprintf(L"AdjustTokenPrivileges error: %u\n", GetLastError() );
return FALSE;
} if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
{
_tprintf(L"The token does not have the specified privilege. \n");
return FALSE;
} return TRUE;
} BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath)
{
HANDLE hProcess = NULL, hThread = NULL;
HMODULE hMod = NULL;
LPVOID pRemoteBuf = NULL;
DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
LPTHREAD_START_ROUTINE pThreadProc; // #1. 使用 dwPID 获取目标进程(notepad.exe)句柄(PROCESS_ALL_ACCESS权限),然后就可以用 hProcess 控制进程.
if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
{ //OpenProcess调用API,借助PID获取目标权限
_tprintf(L"OpenProcess(%d) failed!!! [%d]\n", dwPID, GetLastError());
return FALSE;
} // #2. 在目标进程(notepad.exe) 内存中分配 szDllName 大小的内存,返回 pRemoteBuf 作为该缓冲区的地址.
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE); // #3. 将 myhack.dll 路径写入刚刚分配的缓冲区.
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL); // #4. 获取 LoadLibraryW() API 地址,kernel32.dll在每个进程中的加载地址相同(这个特性就是我们要利用的).
hMod = GetModuleHandle(L"kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW"); // #5. 在 notepad.exe 中运行线程
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread);
CloseHandle(hProcess); return TRUE;
} int _tmain(int argc, TCHAR *argv[])
{
if( argc != 3)
{
_tprintf(L"USAGE : %s <pid> <dll_path>\n", argv[0]);
return 1;
} // change privilege
if( !SetPrivilege(SE_DEBUG_NAME, TRUE) )
return 1; // inject dll
if( InjectDll((DWORD)_tstol(argv[1]), argv[2]) )
_tprintf(L"InjectDll(\"%s\") success!!!\n", argv[2]);
else
_tprintf(L"InjectDll(\"%s\") failed!!!\n", argv[2]); return 0;
}

main()函数的主要功能是检查输入程序的参数,然后调用InjectDll()函数。InjectDll()函数是用 来实施DLL注入的核心函数,其功能是命令目标进程(notepadexe )自行调用LoadLibrary(“myhack.dll”)API。下面逐行详细查看InjectDll()函数。

  • 获取目标进程句柄
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)

调用OpenProcessO API,借助程序运行时以参数形式传递过来的dwPID值,获取notepad.exe进程的句柄(PROCESS_ALL_ACCESS权限)。得到PROCESS_ALL_ACCESS权限后,就可以使用获取的句柄(hProcess )控制对应进程(notepad.exe )0

  • 将要注入的DLL路径写入目标进程内存
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEMCOMMIT, PAGEREADWRITE);

需要把即将加载的DLL文件的路径(字符串)告知目标进程(notepacLexe )。因为任何内存空间都无法进行写入操作,故先使用VirtualAllocEx() API在目标进程(notepad.exe)的内存空间中分配一块缓冲区,且指定该缓冲区的大小为DLL文件路径字符串的长度(含Terminating NULL )即可。

VirtualAllocEx()函数的返回值(pRemoteBuf)为分配所得缓冲区的地址。该地址并不是程序(Inject.exe )自身进程的内存地址,而是hProcess句柄所指目标进程(notepad.exe)的内存地址,请务必牢记这一点。

WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID) szDUName, dwBufSize, NULL);

使用WriteProcessMemory() API将DLL路径字符串(“C:\work\dummy.dll”)写入分配所得缓冲区(pRemoteBuf)地址。WriteProcessMemoryO API所写的内存空间也是hProcess句柄所指的目标进程(notepad.exe )的内存空间。这样,要注入的DLL文件的路径就被写入目标进程(notepad.exe )的内存空间。

Windows操作系统提供了调试API,借助它们可以访问其他进程的内存空间。其中具有代表性的有 VirtualAllocEx()、VirtualFreeEx()、WriteProcessMemory()、ReadProcessMemory()等。

  • 获取LoadLibraryW() API地址
hMod = GetModuleHandle("kernel32 .dll");
pThreadProc = (LPTHREAD_STARTROUTINE)GetProcAddress(hMod, "LoadLibraryW");

调用LoadLibrary() API前先要获取其地址(LoadLibraryW()是LoadLibrary()的Unicode字符串版本)。

最重要的是理解好以上代码的含义。我们的目标明明是获取加载到notepaclexe进程的kernel32.dll的LoadLibraryW() API的起始地址,但上面的代码却用来获取加载到InjectDll.exe进程的kernel32.dll的LoadLibraryW() API的起始地址。如果加载到notepad.exe进程中的kemel32.dll的地址与加载到InjectDll.exe进程中的kemel32.dll的地址相同,那么上面的代码就不会有什么问题。但 是如果kemel32.dll在每个进程中加载的地址都不同,那么上面的代码就错了,执行时会发生内存引用错误。

其实在Windows系统中,kernel32.dll在每个进程中的加载地址都是相同的。

《Windows核心编程》一书中对此进行了介绍,此后这一特性被广泛应用于DLL注入技术。

根据OS类型、语言、版本不同,kernel32.dll加载的地址也不同。并且Vista/7中应用了新的ASLR功能,每次启动时,系统DLL加载的地址都会改变。但是在系统运行期间它都会被映射(Mapping)到每个进程的相同地址。Windows操作系统中,DLL首次进入内存称为“加载”(Loading),以后其他进程需要使用相同DLL时不必再次加载,只要将加载过的DLL代码与资源映射一下即可,这种映射技术有利于提高内存的使用效率。

像上面这样,OS核心DLL会被加载到自身固有的地址,DLL注入利用的就是Windows OS的这一特性(该特性也可能会被恶意使用,成为Windows安全漏洞)。所以,导入InjectDll.exe进程中的LoadLibraryW()地址与导入notepad.exe进程中的LoadLibraryW()地址是相同的。

一般而言,DLL文件的ImageBase默认为0x10000000,依次加载a.dll与b.dll时,先加载的a.dll被正常加载到0x10000000地址处,后加载的b.dll无法再被加载到此,而是加载到其他空白地址空间,也就是说,该过程中发生了 DLL重定位(因为a.dll已经先被加载到它默认的地址处)。

若kemel32.dll加载到各个进程时地址各不相同,那么上述代码肯定是错误的。但实际在Windows操作系统中,kemel32.dll不管在哪个进程都会被加载至相同地址。为什么会这样呢?我借助PEView软件查看了 Windows操作系统的核心DLL文件的 ImageBase值,罗列如下表(Windows XP SP3版本,根据Windows更新不同,各值会有变化)。



微软整理了一份OS核心DLL文件的ImageBase值,防止各DLL文件加载时出现区域重合,这样加载DLL就不会发生DLL重定位了。

  • 在目标进程中运行远程线程(Remote Thread)
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
pThreadProc = notepad.exe进程内存中的LoadLibrary()地址
pRemoteBuf = notepad.exe进程内存中的 “c:\work\myhack.dll” 字符串地址

一切准备就绪后,最后向notepad.exe发送一个命令,让其调用LoadLibraryW() API函数加载指定的DLL文件即可,遗憾的是Windows并未直接提供执行这一命令的API。但是我们可以另辟蹊径,使用CreateRemoteThread()这个API (在DLL注入时几乎总会用到)。CreateRemoteThread()API用来在目标进程中执行其创建出的线程,其函数原型如下:

CreateRemoteThread(
_In_ HANDLE hProcess,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_opt_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_opt_ LPDWORD lpThreadId
);

除第一个参数hProcess外,其他参数与CreateThread()函数完全一样。hProcess参数是要执行线程的目标进程(或称“远程进程”、“宿主进程”)的句柄。IpStartAddress与IpParameter参数分别给出线程函数地址与线程参数地址。需要注意的是,这2个地址都应该在目标进程虚拟内存空间中(这样目标进程才能认识它们)。

初次接触DLL注入技术的读者朋友可能会头昏脑涨、不知所云。本来想向其他进程注入DLL文件,这里为何突然出现线程运行函数呢?仔细观察线程函数ThreadProc()与LoadLibrary()API,可以从中得到一些启示。

// 这里直接搬运了PTHREAD_START_ROUTINE的定义更为准确
typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(
LPVOID lpThreadParameter
);
typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; HINSTANCE LoadLibrary(
LPCTSTR lpLibFileName
// address of filename of executable module
);

两函数都有一个4字节的参数,并返回一个4字节的值。也就是说,二者形态结构完全一样,灵感即源于此。调用CreateRemoteThread()时,只要将LoadLibrary()函数的地址传递给第四个参数IpStartAddress,把要注入的DLL的路径字符串地址传递给第五个参数IpParameter即可(必须是目标进程的虚拟内存空间中的地址)。由于前面已经做好了一切准备,现在调用该函数使目标进程加载指定的DLL文件就行了。

其实,CreateRemoteThread()函数最主要的功能就是驱使目标进程调用LoadLibrary()函数,进而加载指定的DLL文件。

调试方法

首先我们打开一个未注入myhack.dll的notepad



然后利用OD的attach(File->Attach)功能,将notepad(附加)加载进OD



再点Options->Debugging options,将Events中的Break on new module(DLL)打对勾,这样,每当有新的DLL被加载到notepad.exe进程,都会在该DLL的EP处暂停。如此一来,进行DLL注入时也会在该DLL的EP处暂停。



接着我们使用InjectDll.exe将myhack.dll文件注入notepad.exe进程,输入命令后回车







此时调试器将暂停



这时候od暂停的并不是myhack.dll的EP,这是因为加载myhack.dll前,需要先加载它导入的所有DLL文件。我们一直F9运行,直到在myhack.dll的EP处暂停。



双击跟进,这就是myhack.dll的EP地址,如果想跟进调试,在调试前要先取消对"break on new module(DLL)"的勾选。

使用注册表修改AppInit_DLLs实现注入

进行DLL注入的第二种方法是使用注册表,WindowsOS的注册表中默认提供了AppInit_DLLs与LoadAppInit_DLLs两个注册表项



只要将要注入DLL的路径写入AppInit_DLLs项目,并在LoadAppInit_DLLs中设置值为1,重启时,系统就会将指定的DLL注入到所有运行进程中。主要原理是User32.dll被加载到进程时,会读取AppInit_DLLs注册表项,若值为1,就调用LoadLibrary()函数加载用户DLL。所以严格来说,是将注入DLL加载到使用user32.dll的进程中。

注:Windows XP会忽略LoadAppInit_DLLs注册表项。

分析myhack2.dll的源码

// myhack2.cpp
// 主要作用是以隐藏模式运行IE,连接到指定网站 #include "windows.h"
#include "tchar.h" #define DEF_CMD L"c:\\Program Files\\Internet Explorer\\iexplore.exe"
#define DEF_ADDR L"http://www.naver.com"
#define DEF_DST_PROC L"notepad.exe" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
TCHAR szCmd[MAX_PATH] = {0,};
TCHAR szPath[MAX_PATH] = {0,};
TCHAR *p = NULL;
STARTUPINFO si = {0,};
PROCESS_INFORMATION pi = {0,}; si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE; switch( fdwReason )
{
case DLL_PROCESS_ATTACH :
if( !GetModuleFileName( NULL, szPath, MAX_PATH ) )
break; if( !(p = _tcsrchr(szPath, '\\')) )
break; if( _tcsicmp(p+1, DEF_DST_PROC) )
break; wsprintf(szCmd, L"%s %s", DEF_CMD, DEF_ADDR);
if( !CreateProcess(NULL, (LPTSTR)(LPCTSTR)szCmd,
NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS,
NULL, NULL, &si, &pi) )
break; if( pi.hProcess != NULL )
CloseHandle(pi.hProcess); break;
} return TRUE;
}

将上述dll文件复制到某个位置,修改注册表项,将AppInit_DLLs项的值修改为待注入DLL的绝对路径,然后修改LoadAppInit_DLLs注册表项的值为1,重启,运行notepad.exe,就会看到DLL已经被注入。

练习示例myhack2.dll

我踩的坑+未解之谜

这里有一个坑

在众多的DLL注入方法中,使用注册表注入是最简单的一种方式。但是有一点要注意: 被注入的进程时64位,那么注入的DLL也应该是64位,32位对应32位。

注入32位进程,应该修改的注册表键为:

# 将下面注册表的键对应的值设置为要注入的 DLL的路径
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs
# 将下面注册表的键对应的值设置为 1
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\LoadAppInit_DLLs

注入64位进程,应该修改的注册表键为:

# 将下面注册表的键对应的值设置为要注入的 DLL的路径
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\WindowsNT\CurrentVersion\Windows\AppInit_DLLs
# 将下面注册表的键对应的值设置为 1
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\WindowsNT\CurrentVersion\Windows\LoadAppInit_DLLs

按照32位的走一遍

上面说了notepad++.exe是32位,于是就按照32位的顺序走

将要注入的dll文件(myhack2.dll)复制到合适位置,我的复制到了‪

(C:\Users\Zer0\Desktop\1234\myhack2.dll)

根据注册表目录

将下面注册表的键对应的值设置为 1

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs

将下面注册表的键对应的值设置为要注入的 DLL的路径

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\LoadAppInit_DLLs



然而重启系统,使修改生效,之后,并没有找到myhack2.dll



百思不得其解

索性试一下修改64位的注册表



重启,打开notepad++.exe,用process explorer查看,还是没有被注入

(就离谱,猜测还是Windows系统问题

But!第二天我先修改32位注册表,重启,发现还不行,又修改64位注册表,重启,先打开吾爱破解od,调试notepad++.exe,看到myhack2.dll,赶紧去process explorer看看,发现出了!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!









我以为是打开od调试了的缘故,于是!我又重启了,没打开od,直接打开notepad++.exe,用process explorer查看,发现依然有myhack2.dll,表示注入成功与打开od调试没有关系!



一整个迷幻住······坐等大佬解释QAQ

AppInit_DLLs注册表键非常强大,通过它几乎可以向所有进程注入DLL文件。若被注入的DLL出现问题(Bug),则有可能导致Windows无法正常启动,所以修改该AppInit DLLs前务必彻查。

《逆向工程核心原理》之DLL注入的更多相关文章

  1. 《逆向工程核心原理》——DLL注入与卸载

    利用CreateRemoteThread #include <iostream> #include <tchar.h> #include <Windows.h> # ...

  2. 30个类手写Spring核心原理之依赖注入功能(3)

    本文节选自<Spring 5核心原理> 在之前的源码分析中我们已经了解到,依赖注入(DI)的入口是getBean()方法,前面的IoC手写部分基本流程已通.先在GPApplicationC ...

  3. 《逆向工程核心原理》Windows消息钩取

    DLL注入--使用SetWindowsHookEx函数实现消息钩取 MSDN: SetWindowsHookEx Function The SetWindowsHookEx function inst ...

  4. 《逆向工程核心原理》——API HOOK

    编写dll处理hook逻辑,注入到目标进程,实现api hook. Windows10 notepad,通过hook kernel32.dll.WriteFile,实现小写字母转大写保存到文件. ho ...

  5. 《逆向工程核心原理》——IAThook

    hook逻辑写入dll中,注入dll. #include "pch.h" #include <tchar.h> #include "windows.h&quo ...

  6. SSH深度历险(八) 剖析SSH核心原理+Spring依赖注入的三种方式

           在java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依 ...

  7. 《逆向工程核心原理》——通过调试方式hook Api

    1.附加目标进程, 2.CREATE_PROCESS_DEBUG_EVENT附加事件中将目标api处设置为0xcc(INT 3断点) 3.EXCEPTION_DEBUG_EVENT异常事件中,首先判断 ...

  8. 逆向工程核心原理-IA-32寄存器

    IA-32由四类寄存器组成:通用寄存器,段寄存器,程序状态与控制寄存器,指令指针寄存器. 通用寄存器:用于传送和暂存数据,也可参与算数逻辑运算,并保存运算结果. EAX(0-31) 32位      ...

  9. 《逆向工程核心原理》——TLS回调函数

    pe中TLS(thread local storage)中函数的执行时机早于入口函数(entry point), 相关结构: // // Thread Local Storage // typedef ...

  10. dll注入及卸载实践

    三种方法:具体详见<逆向工程核心原理>. 1.创建远程线程CreateRemoteThread() 2.使用注册表AppInit_DLLs 3.消息钩取SetWindowsHookEx() ...

随机推荐

  1. Tomcat长轮询原理与源码解析

    Tomcat长轮询原理与源码解析 系列文章目录和关于我 零丶长轮询的引入 最近在看工作使用到的diamond配置中心原理,发现大多数配置中心在推和拉模型上做的选择出奇的一致选择了基于长轮询的拉模型 基 ...

  2. Lambda表达式和链式编程

    一.Lambda表达式 1. Lambda使用条件 Lambda表达式是 JDK8 的一个新特性,可以认为是对匿名内部类的一种简化,但不是所有的匿名内部类都可以简化为Lambda表达式. 只有函数式接 ...

  3. 快速上手Linux核心命令(七):Linux系统信息相关命令

    目录 前言 uname 显示系统信息 hostname 显示或设置系统主机名 du 统计磁盘空间使用情况 echo 显示一行文本 watch 监视命令执行情况 stat whereis 显示命令及其相 ...

  4. [Pytorch框架] 2.1.4 数据的加载和预处理

    文章目录 PyTorch 基础 :数据的加载和预处理 Dataset Dataloader torchvision 包 torchvision.datasets torchvision.models ...

  5. html5和css3基础学习笔记

    网页简介 一个页面包括结构.表现.行为三个部分. 结构:HTML用于描述页面的结构. 表现:CSS用于控制页面中元素的样式. 行为:JavaScript用于响应用户操作. 第一部分 HTML 5(Hy ...

  6. 【Azure 应用服务】Azure JS Function 异步方法中日志无法输出问题引发的(await\async)关键字问题

    问题描述 开发 Azure JS Function(NodeJS),使用 mssql 组件操作数据库.当SQL语句执行完成后,在Callback函数中执行日志输出 context.log(" ...

  7. 聊一聊redis十种数据类型及底层原理

    概述 Redis 是一个开源的高性能键值数据库,它支持多种数据类型,可以满足不同的业务需求.本文将介绍 Redis 的10种数据类型,分别是 string(字符串) hash(哈希) list(列表) ...

  8. 使用 shell 脚本自动申请进京证 (六环外) —— debug 过程

    问题现象 用 shell 脚本写了一个自动办理六环外进京证的工具 <使用 shell 脚本自动申请进京证 (六环外)>,然而运行这个脚本总是返回以下错误信息: { "msg&qu ...

  9. Syncthing 忽略模式

    忽略模式 概要 .stignore 描述 这是 Syncthing 同步文件夹的忽略模式语法指南 语法 .stignore 文件可包含一系列路径匹配模式,对指定文件的处理方式由第一个匹配到它的模式决定 ...

  10. 2023-04-30:用go语言重写ffmpeg的resampling_audio.c示例,它实现了音频重采样的功能。

    2023-04-30:用go语言重写ffmpeg的resampling_audio.c示例,它实现了音频重采样的功能. 答案2023-04-30: resampling_audio.c 是 FFmpe ...