Chapter 3. Principles of anti-dump
"When we step into the same river, we do not exist. "
---- Heraclitus
Things tend to be like this. They need both positive and negative sides in development. They are opposites. The previous dump is basically similar to a lordpe function. Now we need to analyze how a program anti-dump works, at the same time, we will also provide some simple solutions.
Note: The methods mentioned below are all executed in the NT kernel and do not involve 9X.
1. Correct imagesize
Here we will first discuss one of lordpe's correct imagesize functions.
First, we need to know how this anti-attack is generated. According to the above introduction, we know that the image size we get is a snapshot of the moduleentry32 structure, but where does this structure obtain the data?
The answer is obtained through the peb (process environment block) process environment module. Below is the structure of peb.
Struct _ peb (sizeof = 488)
+ 000 byte inheritedaddressspace
+ 001 byte readimagefileexecoptions
+ 002 byte beingdebugged
+ 003 byte sparebool
+ 004 void * Mutant
+ 008 void * imagebaseaddress
+ 00c struct _ peb_ldr_data * LDR
+ 010 struct _ rtl_user_process_parameters * processparameters
+ 014 void * subsystemdata
+ 018 void * processheap
+ 01c void * fastpeblock
+ 020 void * fastpeblockroutine
+ 024 void * fastpebunlockroutine
+ 028 uint32 environmentupdatecount
+ 02c void * kernelcallbacktable
+ 030 uint32 systemreserved [2]
+ 038 struct _ peb_free_block * freelist
+ 03c uint32 tlsexpansioncounter
+ 040 void * tlsbitmap
+ 044 uint32 tlsbitmapbits [2]
+ 04c void * readonlysharedmemorybase
+ 050 void * readonlysharedmemoryheap
+ 054 void ** readonlystaticserverdata
+ 058 void * ansicodepagedata
+ 05c void * oemcodepagedata
+ 060 void * unicodecasetabledata
+ 064 uint32 numberofprocessors
+ 068 uint32 ntglobalflag
+ 070 union _ large_integer criticalsectiontimeout
+ 070 uint32 lowpart
+ 074 int32 highpart
+ 070 struct _ unnamed3 u
+ 070 uint32 lowpart
+ 074 int32 highpart
+ 070 int64 quadpart
+ 078 uint32 heapsegmentreserve
+ 07c uint32 heapsegmentcommit
+ 080 uint32 heapdecommittotalfreethreshold
+ 084 uint32 heapdecommitfreeblockthreshold
+ 088 uint32 numberofheaps
+ 08c uint32 maximumnumberofheaps
+ 090 void ** processheaps
+ 094 void * gdisharedhandletable
+ 098 void * processstarterhelper
+ 09c uint32 gdidcattributelist
+ 0a0 void * loaderlock
+ 0a4 uint32 osmajorversion
+ 0a8 uint32 osminorversion
+ 0ac uint16 osbuildnumber
+ 0ae uint16 oscsdversion
+ 0b0 uint32 osplatformid
+ 0b4 uint32 imagesubsystem
+ 0b8 uint32 imagesubsystemmajorversion
+ 0bc uint32 imagesubsystemminorversion
+ 0c0 uint32 imageprocessaffinitymask
+ 0c4 uint32 gdihandlebuffer [34]
+ 14C function * postprocessinitroutine
+ 150 void * tlsexpansionbitmap
+ 154 uint32 tlsexpansionbitmapbits [32]
+ 1d4 uint32 sessionid
+ 1d8 void * appcompatinfo
+ 1dc struct _ unicode_string csdversion
+ 1dc uint16 Length
+ 1de uint16 maximumlength
+ 1e0 uint16 * Buffer
We can get the first address of this peb from FS: [30. Then, the _ peb_ldr_data * LDR at 0C is the key. We can access
Typedef struct _ peb_ldr_data {
Ulong length;
Boolean initialized;
Pvoid sshandle;
List_entry inloadordermodulelist;
List_entry inmemoryordermodulelist;
List_entry ininitializationordermodulelist;
} Peb_ldr_data, * ppeb_ldr_data;
The last three Members of this structure are pointers to the corresponding three two-way linked list headers in the ldr_module linked list structure, they are pointers to the module information structure arranged in the loading order, the address order in the memory, and the initialization order. Therefore, we can access the _ ldr_module structure, which includes the sizeofimage of the process.
_ Ldr_module structure:
Typedef struct _ ldr_module {
List_entry inloadordermodulelist;
List_entry inmemoryordermodulelist;
List_entry ininitializationordermodulelist;
Pvoid baseaddress;
Pvoid entrypoint;
Ulong sizeofimage; // process's image size
Unicode_string fulldllname;
Unicode_string basedllname;
Ulong flags;
Short loadcount;
Short tlsindex;
List_entry hashtableentry;
Ulong timedatestamp;
} Ldr_module, * pldr_module;
Therefore, the key code we get is:
//////////////////////////////////////// //////////////////////////////////////// ////
// Several codes here are the key to modifying peb
_ ASM
{
MoV eax, FS: [30 h] // obtain the peb address
MoV eax, [eax + 0ch] // + 00c struct _ peb_ldr_data * LDR
MoV eax, [eax + 0ch] // _ ldr_module's first address
MoV dword ptr [eax + 20 h], 1000 h // eax + 20 is the place where the image size is saved
}
//////////////////////////////////////// //////////////////////////////////////// ////
The function of the above Code is to change the image size to 1000 h, so that the size obtained using moduleentry32 is inaccurate. Therefore, when tracking the shell, you must be especially careful with the above several lines of code. Skip this step if you see it.
Now, I know how it is anti. Later, let's see how lordpe uses correct imagesize. I tracked its code slightly. The following API functions are found:
1. getprocessbasesize
2. getprocesspath
3. createfilea
4. readfile
You may know what's going on here. After obtaining the absolute path, he opened the PE file on the disk and read the imagesize of the PE Header to correct the incorrect image size. Well, maybe you will say, I will write an anti code to modify the imagesize of the PE File Header so that it still gets wrong. I have to remind you that any operations on files are dangerous. Let's imagine this situation: when you open the original PE file and write an incorrect imagesize into the PE file, the lordpe's correct imagesize is still reactive, in a certain place, I plan to open the file again and write the correct information back to the PE file. (Otherwise, you will not want to open it next time.) Not to mention that this method is cumbersome. Let's imagine that at this time, your machine will crash! You have to restart the machine. Your final work is not over yet. So in addition to the author of anti, you should never open your PE file without knowing why.
Therefore, a smart programmer will not do such dangerous things. Okay. Let's see how I implemented this function. I added a button "correct size" based on the original one. Then a function is redefined to implement this function:
Bool correctsizefunc (hwnd hdlg, hwnd hwindlist)
{
// The function can obtain the sizeofimage In the PE Header of the file as the correct sizeofimage
Lpctstr file_name = NULL;
Wparam TMP = (wparam) sendmessage (hwindlist, lb_getcursel, 0, 0 );
If (TMP = lb_err)
{
MessageBox (hdlg, text ("Please choose a process..."), text ("Oh... No, no, no..."), mb_ OK );
Return false;
}
DWORD idprocess = sendmessage (hwindlist, lb_getitemdata, TMP, 0); // obtain the process ID in this ticket
Id = idprocess; // The global variable ID is used to control switching between different processes.
File_name = getfilepath (hdlg, idprocess );
If (! File_name)
Return false;
// Open the file
Handle hfile;
Hfile = createfile (file_name, generic_read, 0, 0, open_existing, file_attribute_normal, null );
If (hfile = invalid_handle_value)
{
Return false;
}
// Create a file ing Kernel Object
Handle hmapping;
Hmapping = createfilemapping (hfile, null, page_readonly, 0, 0, null );
If (hmapping = NULL)
{
Closehandle (hfile );
Return false;
}
// Create a file view
Lpvoid imagebase;
Imagebase = mapviewoffile (hmapping, file_map_read, 0, 0 );
If (imagebase = NULL)
{
Closehandle (hmapping );
Return false;
}
// The following code finds the sizeofimage from the PE Header of the file.
Pimage_dos_header doshead = NULL;
Pimage_nt_headers32 pntheader = NULL;
Pimage_file_header pfileheader = NULL;
Pimage_optional_header poptionalheader = NULL;
Pimage_section_header pseheader header = NULL;
Doshead = (pimage_dos_header) imagebase;
Pntheader = (pimage_nt_headers32) (DWORD) imagebase + doshead-> e_lfanew );
Poptionalheader = & pntheader-> optionalheader;
Sizeofimage = (INT) poptionalheader-> sizeofimage;
// Output the result after finding it
Char szbuffer [100];
Char szmsg [] = "the original image size is: % 08x \ n the adjusted image size is: % 08x ";
Wsprintf (szbuffer, szmsg, getsizeofimage (hdlg, idprocess), sizeofimage );
MessageBox (hdlg, szbuffer, text ("correction result"), mb_ OK );
Closehandle (hmapping );
Closehandle (hfile );
Sleep (200 );
Return true;
}
The implementation of this function is very simple, but at the same time, it should be emphasized that there were some minor problems when I was coordinating and correcting different processes than the dump process. I used a very stupid way to define a global variable ID to control the occurrence of such a thing.
Ii. Practice
This modify_module_imagesize program includes the above Code for modifying the image size in peb. Run it:
We can see that the original image size has been modified.
Now let's try dump.
In this way, we can dump it to get the original c000 process.
Ii. Other anti Methods
Based on the above moduleentry32 structure, we can get a lot of inspiration. After all, if you understand the principles, it is not difficult to find an anti-attack solution. The first is the base address. Can we modify the base address in peb?
In fact, this method will cause unnecessary trouble. That is to say, it is not feasible.
Another method is to modify the file path, which is good. But it can only be used in 9x, because so far, we do not know this method in the NT kernel. So I will not introduce it here. Interested readers can go to see the Software Encryption technology insider P204-P207, where hying has a complete introduction.
The following describes a very common and commonly used method. Is to use the Memory attribute for.
We know that if we open a process, we must obtain the proper read permission to read and write the content in the process. In fact, when an EXE file is loaded into the memory, all its fetch segments have the right to read, and it is in this way that we can read it out of the memory, write to the disk file. Therefore, we have anti. If we modify the permission of some segments, We will cancel the read permission. What will happen?
Let's make a simple experiment!
/*------------------------------------------------------------------------
Save as modify_the_read_right.cpp
(C) lenus marggin 2005 10.15
-------------------------------------------------------------------------*/
# Include <windows. h>
# Include <iostream. h>
# Include <stdio. h>
Void main ()
{
DWORD dwoldprotect;
Hmodule imagebase = getmodulehandle (null );
Virtualprotect (imagebase, 1000, page_noaccess, & dwoldprotect); // you can change the PE Header to an inaccessible attribute.
Cout <"the pe head read right change to no_access !! "<Endl;
Cout <"u can try to dump at here! "<Endl;
Getchar ();
}
After running it, let's use lordpe to dump it and find out something? A classic dialog box!
I believe you have seen this. Let's take a look at the 400000 points in this process!
Select process --- Right click --- dump region to view the above window. It turns into the noaccess attribute.
How can this problem be solved? We need a stronger tool. Now we will use OD's ollydump to dump it!
Run F9 after loading with od! Well, we can still see the noaccess attribute above with lordpe, but what is the result in the OD memory image?
We can see that it is still readable, writable, and executable.
Why?
The OD debugger needs to edit the data in the space of the process. However, if a segment is inaccessible due to noaccess, it is hard to edit it. So when we need to use this space, he will temporarily modify its attributes to the complete permissions. After we use it, what will happen? Then, we can say that the ring3 debugger is always doing this kind of thing, for example, the placement of int3. From these aspects, we can also appreciate the power of OD.
Now, you can use ollydump to dump it down.
Iv. Summary
Summary. For the anti chapter, the above are just some common methods. As a matter of fact, the contest of contradictions will never stop, As Heraclitus at the beginning said, "We cannot step into the same river, and we exist and do not exist. "In philosophy, things are the unity of contradictions. There is no such competition or any possibility. In the world of encryption and decryption, anti-dump is also a university question. As a result, we will find many clever methods while avoiding.