DLL学习摘录5

来源:互联网 发布:如何设计分销数据库 编辑:程序博客网 时间:2024/04/27 15:54

1

injecting a DLL using windows Hooks

   In Microsoft Windows, each process gets its own private address space. When you use pointers to reference memory, the value of the pointer refers to a memory address in your own process' address space. Your process cannot create a pointer that references memory belonging to another process. So if your process has a bug that overwrites memory at a random address, the bug can't affect the memory used by another process.

 

Situations that require breaking through process boundary walls to access another process' address space include the following:

  • When you want to subclass a window created by another process

  • When you need debugging aids—for example, when you need to determine which dynamic-link libraries (DLLs) another process is using

  • When you want to hook other processes

 

2

 

在一个应用程序中,我们可以调用SetWindowLongPtr(hWnd, GWLP_WNDPROC, MySubclassProc), 这个函数可以拦截发送给hWnd窗口的消息, 也就是说, 以后hWnd窗口的消息不会再由它原来的窗口函数来处理了,而是交给MySubclassProc函数来处理了.

那么我们可不可以在Process B中调用FindWindow来获取Process A的窗口句柄, 然后调用SetWindowLongPtr来让MysubclassProc函数来接收处理这个窗口的消息呢?

答案是不可以。 如果要实现这样的目标, 我们必须想办法将MysubclassProc函数的代码弄到 Process A 的地址空间中去。那么怎么才能将一个函数的代码弄到别的进程的空间中去呢?我们自然想到了LoadLibrary()函数, 我们把MysubclassProc()函数写在一个DLL中,然后想办法把这个DLL载入到目标进程中。我们把这种技术叫做“注射”(Injecting).

 

3

There are several ways to injecting a DLL into a process

  A: Injecting a DLL Using the Registry.

  B: Injecting a DLL Using Windows Hooks

      如果你想利用Hooks去截获其他进程的消息的话,你可以写一个DLL,其中有一个函数GetMsgProc,它用来处理截获的消息。

      然后你在PROCESS A中调用HHOOK hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hInstDll, 0);

      WH_GETMESSAGE代表HOOK的类型。

      GetMsgProc代表处理函数。

      hInstDll代表DLL在本进程的中地址。

      0代表想要HOOK的线程ID。(这里所有ID。)

      当OS发现了你想要HOOK的消息时,会把该DLL载入到目标进程的地址空间中,并调用其中的GetMsgProc函数。

      那么PROCESS A如何能得到process B中GetMsgProc的相关结果呢?

      可以使用"内存共享技术". 这样技术可以让你在两个exe之间交换任意的数据.

      为了方便程序员操作, windows提供了

     LRESULT SendMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );

     这个函数可以在进程之间发送数据.

     message为WM_COPYDATA.  wParam是目标窗口句柄。lParam是一个copydatastruct结构:

    COPYDATASTRUCT

typedef struct tagCOPYDATASTRUCT {

DWORD



dwData





;

DWORD



cbData





;

PVOID



lpData





;

} COPYDATASTRUCT;



Members

dwData
Specifies up to 32 bits of data to be passed to the receiving application.
cbData
Specifies the size, in bytes, of the data pointed to by the lpData member.
lpData
Long pointer to data to be passed to the receiving application. This member can be NULL.

 

     注意:

     1 你所要安装的类型有很多种,比如WH_GETMESSAGE,WH_CALLWNDPROC,WH_KEYBOARD等等。

        对于每一种hook,处理函数都有一个固定的名称和参数,比如hook类型为WH_GETMESSAGE, 那么第二个hook

        procedure的名字一定要是GetMsgProc,且它的三个参数也是OS定义好的。

     2 CallNextHookEx(). 在一个OS中,有时不止你一个人要HOOK.可能也有别人在HOOK,如果你想在自己HOOK后也让

        别人的HOOK起作用的话,就调用CallNextHookEx()函数。

     3 你的hook procedure处理完后,用显示的调用一个东西以让OS按原理的方式接着处理吗?

 

  C: Injecting a DLL Using Remote Threads

      在HOOKS中,由OS帮我们把DLL载入到了目标进程的地址空间中去了。本方法中我们自己动手DLL载入到目标进程中去。

      如果我们可以在LoadLibrary()中指定目标进程的话就最方便了,可惜WINDOWS没有提供相关功能。但是WINDOWS提供了

      另外一个函数CreatRemoteThread(),这个函数可以让我们在目标进程中创建一个线程。还可以指定这个线程函数。但是这个线程函数的代码一定要

      存在于目标进程的地址空间中!

我们可以这样做:

HANDLE hThread = CreateRemoteThread(hProcessRemote, NULL, 0, LoadLibraryW, L"C://MyLib.dll", 0, NULL);

这样我们的MyLib.dll就被载入到目标进程的地址空间中去了。

这个语句能够成功执行的原理是:

    一 LoadLibraryW()函数存在于Kernel32.dll中,目标进程执行时一定会把该DLL载入。所以LoadLibraryW()存在于目标进程中了。

    二 我们用CreatRemoteThread()创建线程,那么这个线程函数的格式是有规定的:DWORD WINAPI ThreadFunc(PVOID pvParam);

        而LoadLibraryW的原形和它基本一致。

 

这样做还存在两个问题:

    一

If you use a direct reference to LoadLibraryW in the call to CreateRemoteThread, this resolves to the address of the LoadLibraryW thunk in your module's import section. Passing the address of the thunk as the starting address of the remote thread causes the remote thread to begin executing who-knows-what. The result is most likely an access violation. To force a direct call to the Load-LibraryW function, bypassing the thunk, you must get the exact memory location of Load-LibraryW by calling GetProcAddress.

The call to CreateRemoteThread assumes that Kernel32.dll is mapped to the same memory location in both the local and remote processes' address spaces. Every application requires Kernel32.dll, and in my experience the system maps Kernel32.dll to the same address in every process, even if this address might change between two reboots as you have seen with Address Space Layout Randomization (ASLR) in Chapter 14, "Exploring Virtual Memory." So we have to call CreateRemoteThread like this:

// Get the real address of LoadLibraryW in Kernel32.dll.



PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)



GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");



HANDLE hThread = CreateRemoteThread(hProcessRemote, NULL, 0,



pfnThreadRtn, L"C://MyLib.dll", 0, NULL);



 二

All right, this fixes one problem. But I said that there were two problems. The second problem has to do with the DLL pathname string. The string, "C://MyLib.dll", is in the calling process' address space. The address of this string is given to the newly created remote thread, which passes it to LoadLibraryW. But when LoadLibraryW dereferences the memory address, the DLL pathname string is not there and the remote process' thread will probably raise an access violation; the unhandled exception message box is presented to the user, and the remote process is terminated. That's right, the remote process is terminated—not your process. You will have successfully crashed another process while your process continues to execute just fine!

To fix this, we need to get the DLL's pathname string into the remote process' address space. Then, when CreateRemoteThread is called, we need to pass it the address (relative to the remote process) of where we placed the string. Again, Windows offers a function, VirtualAllocEx, that allows one process to allocate memory in another process' address space:

PVOID VirtualAllocEx(

 HANDLE hProcess,

PVOID pvAddress,

SIZE_T dwSize,

DWORD flAllocationType,

 DWORD flProtect);



Another function allows us to free this memory:
BOOL VirtualFreeEx(

HANDLE hProcess,

PVOID pvAddress,

SIZE_T dwSize,

DWORD dwFreeType);

Both of these functions are similar to their non-Ex versions (which are discussed in Chapter 15, "Using Virtual Memory in Your Own Applications"). The only difference is that these two functions require a handle to a process as their first argument. This handle indicates the process where the operation is to be performed.

Once we allocate memory for the string, we also need a way to copy the string from our process' address space over to the remote process' address space. Windows offers functions that allow one process to read from and write to another process' address space:

BOOL ReadProcessMemory(

HANDLE hProcess,

LPCVOID pvAddressRemote,

PVOID pvBufferLocal,

SIZE_T dwSize,

SIZE_T* pdwNumBytesRead);



BOOL WriteProcessMemory(

HANDLE hProcess,

PVOID pvAddressRemote,

LPCVOID pvBufferLocal,

SIZE_T dwSize,

SIZE_T* pdwNumBytesWritten);

The remote process is identified by the hProcess parameter. The pvAddressRemote parameters indicate the address in the remote process, pvBufferLocal is the address of memory in the local process, dwSize is the requested number of bytes to transfer, and pdwNumBytesRead and pdwNumBytesWritten indicate the number of bytes actually transferred; these values can be examined after the function returns.

so

Now that you understand all that I'm trying to do, let me summarize the steps you must take:

  1. Use the VirtualAllocEx function to allocate memory in the remote process' address space.

  2. Use the WriteProcessMemory function to copy the DLL's pathname to the memory allocated in step 1.

  3. Use the GetProcAddress function to get the real address (inside Kernel32.dll) of the LoadLibraryW or LoadLibraryA function.

  4. Use the CreateRemoteThread function to create a thread in the remote process that calls the proper LoadLibrary function, passing it the address of the memory allocated in step 1. At this point, the DLL has been injected into the remote process' address space, and the DLL's DllMain function receives a DLL_PROCESS_ATTACH notification and can execute the desired code. When DllMain returns, the remote thread returns from its call to Load-LibraryW/A back to the BaseThreadStart function (discussed in Chapter 6, "Thread Basics"). BaseThreadStart then calls ExitThread, causing the remote thread to die.

    Now the remote process has the block of storage allocated in step 1 and the DLL still stuck in its address space. To clean this stuff up, we need to execute the following steps after the remote thread exists:

  5. Use the VirtualFreeEx function to free the memory allocated in step 1.

  6. Use the GetProcAddress function to get the real address (inside Kernel32.dll) of the FreeLibrary function.

  7. Use the CreateRemoteThread function to create a thread in the remote process that calls the FreeLibrary function, passing the remote DLL's HMODULE.

That's basically it.

为什么不可以在CreatRemoteThread()中直接指定函数loadlibrary, 而是要指定loadlibraryA或loadLibraryW?

 

因为在kernel32.dll中没有loadlibrary,只有loadlibraryA或loadlibraryW.

在process B中可以调用loadlibrary是因为在process B中定义有相关的宏,

HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName);HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName);#ifdef UNICODE#define LoadLibrary LoadLibraryW#else#define LoadLibrary LoadLibraryA#endif // !UNICODE

 

 

 

D:

Injecting a DLL with a Trojan DLL

 

 

总结:

     1 进程之间是不能互相影响的,比如进程A中的一个指针是0x11002233, 那么它所指向的一定是进程A中的该地址。

     2 进程之间可以共享数据,利用“内存映射文件”的方法。但是比如进程B中的0x11002233指向的是一段代码,进程B把这段代码

     放到“内存映射文件”中了,进程A到其中取到了该值,然后调用0x11002233处的代码,那么这个代码也不是进程B中的那个代码,而

     是进程A中的0x11002233处的代码。

     3 如果想实现让进程A调用进程B中的代码,那么我们要把进程B中的那段代码放在一个DLL文件中,然后想办法把那个DLL映射到进程A

     的地址空间中来才行。利用Hook技术的话,是系统帮我们把DLL载入到目标程序中。如果利用远程注入的方法,是我们自己写代码来

     实现把DLL载入到目标程序中。

     4 进程之间不能互相影响也仅限于1中所述的情形而已。其它的功能都可以实现的,比如你可以在process A中调用VirtualAllocEx()在

        process B中申请一段地址空间。调用 VirtualFreeEx()释放一段空间。

 

Windows offers functions that allow one process to read from and write to another process' address space:

BOOL ReadProcessMemory(

PS: postthreadmessage()可以向一个线程发送自定义消息。

 

 

API hooking:

这一节还没看.

 

原创粉丝点击