D2hackmap has an integrity scan function to check whether the game process code has been changed. This function is applicable to d2hackmap's secure open map. The so-called "Safe map opening" principle is to allocate a space in the game process and inject the Code related to the "map opening" (not a complete DLL module) into the space, this code runs under the main thread context of the game. It calls the internal function of the game to implement the "Open Map" logic, and then releases the allocated space. This process takes a short time and does not need to modify the code of the game process. Therefore, it is highly secure and cannot be easily captured by Warden. Warning before running the "safe open map" code:
The Code logic of reveal map is roughly as follows. The red code line calls the internal functions of the game:
Void _ stdcall remoterevealautomapact (revealmapcontext * pctx)
{
Automaplayer2 * player;
Unitany * unit = * pctx-> p_d2client_playerunit;
If (! Unit |! Unit-> PPOs-> proom1) return;
DWORD currlvl = unit-> PPOs-> proom1-> proom2-> pdrlglevel-> nlevelno;
DWORD act = 0;
Byte actlvls [] = {1, 40, 75,103,109,133,134,135,136,137 };
Do {} while (currlvl> = actlvls [++ Act]);
Dword lvl = currlvl;
For (LVL = actlvls [Act-1]; LVL <actlvls [Act]; LVL ++ ){
Drlglevel * pdrlglevel = pctx-> getdrlglevel (* pctx-> p_d2client_pdrlgact)-> pdrlgmisc, LVL );
If (! Pdrlglevel)
Pdrlglevel = pctx-> d2common_getdrlglevel (* pctx-> p_d2client_pdrlgact)-> pdrlgmisc, LVL );
If (! Pdrlglevel-> proom2first ){
Pctx-> d2common_initdrlglevel (pdrlglevel );
}
Player = pctx-> d2common_getdrlglayer (LVL );
Pctx-> initautomaplayer (player-> nlayerno, (DWORD) pctx-> d2client_initautomaplayer_ I );
Pctx-> revealautomaplevel (pctx, pdrlglevel );
}
Player = pctx-> d2common_getdrlglayer (currlvl );
Pctx-> initautomaplayer (player-> nlayerno, (DWORD) pctx-> d2client_initautomaplayer_ I );
}
Because the game's internal functions need to be called to open a map, this leaves a little room for Warden Detection: If warden intercepts one of these internal functions, when a call occurs, check the identity of the caller (obtain the call module information through the return address of the analysis function) to capture the plug-in. In d2hackmap, d2hackmap checks the integrity of game processes before executing the "safe open map" Code to deal with such warden detection, that is, check whether the game process code has been changed. This article describes the implementation of "integrity check.
The first thing to note is that the "integrity check" mentioned here mainly refers to checking the code integrity. An executable program consists of a file header, code segment, and data segment. The code of the program does not change during running. It is generally loaded on the read-only memory page. The data segment can be divided into read-only data and read/write data. Read/write data can be loaded into the read/write Memory Page. From a general point of view, this part of data cannot be used for integrity check. The d2hackmap integrity check function queries the read-only memory page of the executable module (exe, DLL), including the code segment and read-only data segment.
It is common to load dozens of DLL files in a Windows process. With the EXE main program module, the data size to be checked for integrity check is generally between several megabytes and dozens of megabytes. A good detection algorithm is necessary for such data volumes. D2hackmap uses a policy to create a "clean" module for each module to be scanned, and then compare the two modules by byte. In x86, the memory has dedicated and efficient compilation commands cmpsd and cmpsb.
DWORD _ declspec (naked) _ fastcall mymemcmpd (DWORD nsize, void * pleft, void * pright)
{
_ ASM
{
Push ESI;
Push EDI;
SHR ECx, 2;
MoV eax, EDX;
MoV ESI, EDX; // pleft
MoV EDI, [esp + 0x0c]; // pright
Rep cmpsd;
Sub eax, ESI;
Neg eax;
Pop EDI;
Pop ESI;
RET 4;
}
}
DWORD _ declspec (naked) _ fastcall mymemcmpb (DWORD nsize, lpbyte pleft, lpbyte pright)
{
_ ASM
{
Push ESI;
Push EDI;
MoV eax, EDX;
MoV ESI, EDX;
MoV EDI, [esp + 0x0c];
Rep cmpsb;
Test ECx, ECx;
JZ notfound;
Sub eax, ESI;
Not eax;
Pop EDI;
Pop ESI;
RET 4;
Notfound:
XOR eax, eax;
Pop EDI;
Pop ESI;
RET 4;
}
}
The key to the problem is how to build a "clean" module, which is very similar to the "module reconstruction" mentioned in the hacker's counterattack, the only difference is that the Code of "module reconstruction" runs in the game process and is in the same memory space as the target module.
The algorithm steps for building a "clean" module are similar to those for manually loading DLL, as described below:
1. copy the data of the target module to the local process space (readprocessmemory), which is called the "dirty" module;
2. Allocate a space to store the "clean" module.
3. Map the disk files of the target module to the local process space (createfile/createfilemapping/mapviewoffile), which is called the disk file image;
4. Copy the "dirty" module data to the "clean" module space (memcpy)-This ensures that the writable data segments are the same;
5. Copy the executable file header (PE Header) of the disk file image to the "clean" module (memcpy)-PE Header for detection;
6. Analyze the PE Header and copy the read-only sections in the disk file image one by one to the "clean" module-read-only sections need to be checked;
7. Next, we will further fix the "clean" module, including the import table (IAT) and relocation table );
8. IAT correction is a little complicated. It is also different from normal DLL loading. The main problem is the same DLL, loading locally may be different from loading a base on a game process. For the DLL linked to in IAT, the modification should be based on the base address that the DLL loads in the target game process;
9. The correction of the relocation table is similar. The "dirty" module should be used to relocate data-which is different from the normal DLL loading.
After these steps, the "clean" module is built. The next integrity check will use the mymemcmpd and mymemcmpb functions provided above. Using this method, the integrity check efficiency is relatively high. Generally, it takes several seconds (<5 seconds) to scan a process. Is the d2hackmap plug-in (d2hackmap. DLL) after the injection, you can see d2hackmap. DLL has been modified many times. Each item in the view lists the modified DLL names (in d2win. DLL), modify the address, modify the length, and the modified command. If it is a jump command, the name of the jump module is also provided (d2hackmap is used in all the commands. DLL. Based on this, we can determine that it is d2hackmap. DLL modified ).
The check can also be used for many other purposes, not only for game plug-ins. For example, some rogue software may intercept some APIs in some sensitive processes to monitor users' behaviors. Integrity Checks can detect these Apis. In addition, the integrity check can also be used to analyze programs that rely on the Code interception technology. For example, you want to analyze d2jsp. DLL implementation technology, it is very effective to conduct Reverse Analysis Based on interception points by observing its interception points. Is the integrity check result after loading d2jsp: