Continued DLL file hookapi author Bin
Some time ago, I have a question on 9CBS. How to make the delete file, copy file, and change file names in Windows? There is a way to implement this operation by intercepting the I / O interrupt of the system. But because netizens just ask how to fail under Windows, then we can also intercept the API function. It is well known that file operations under Windows are generally implemented by calling the WinAPI function, and then updated the final file operation by calling the I / O interrupt of the WinAPI function. If we stop it when you call the WinApi function, do you invalidate the file operation? One problem in front of us is that what method we use to achieve hookapi functions, with a total of two: soft mode and hard mode (huh, I am named). What is the soft mode? Soft mode is to write the program to automatically obtain the RVA (relative virtual address) we want to get the API function, then write to our code at the address, make the program to perform our code first, return Implement the original code, don't look at me, but actually operate very troubles, if the program must enter the Ring0 privilege level when changing the original API code, the problem will be placed in front of you; hard mode refers to the software on hand Change the DLL file directly. Due to the trouble of soft mode and get RING0 privilege levels in 2000, we will talk about how to use hard mode to achieve our expectation. System commonly used API functions are basically in GDI32.DLL, KERNEL32.DLL and SHELL32.DLL three files, and we can know which aspect of the API function in each DLL file is used by file name. Here we have to intercept the API function is SHFILEOPERATION, which is the use of the function in shell32.dll This function is deleted, copy the file, mobile file, rename the file. He has a parameter that is a pointer to the SHFileopStruct structure, which is defined in the ASM as follows: SHFILEOPSTRUCT HWND DWORD?; The caller's window handle WFUNC DWORD?; Specify what action. (Copy, delete, etc.) PFROM DWORD?; Source directory or file PTO DWORD?; Directory or file fflags fileop_flags?; Operating file flag FanyOperationSaborted DWORD DWORD?; Whether to interrupt hnamemappings dWord?; Not common SHFILEOPSTRUCT ENDS
Details about this structure can be obtained by reviewing MSDN.
Ok, the function name also knows, which file is also known. How do you do next step? We can only find this function in the position in shell32.dll, inserting RET 4 in his head. This statement can be. Why insert this statement? We don't need any response to delete files, copy files, etc., you can only return this API function, you can return it immediately, because this function has a parameter, in order to restore the stack to the original, the stack pointer needs to be added 4. Everything is ready, I only owe the address of this function in the DLL file. To know its location, we can write a procedure yourself, calculate it, but now I have a ready-made, why should I edit one? ? ? ? ? Open the getModule program, this program can get a function of the RVA address in a DLL. In the software, enter the "shell32.dll" in the DLL name box, type "shfileOperation" in the input function name box, press the get, get the address: 7fcedcf1h (possibly due to the difference between 98 version, the value here will not be the same Note: This software is case sensitive.). We have to have the software used for shell32.dll files, which is HIEW. The address displayed in this software refers to the offset address inside the file, so we also need to convert the RVA address into a file internal offset address. Open the second software RVA Converter Click on the "LOAD" option in the menu "file", select the file "shell32.dll" we want to load, and then type the RVA address you just got below, type it, The address shown in the file box: 3DCF1 "SHFileOperation" function in the "shell32.dll" file offset address. The most critical step start, open the HIEW software, load "shell32.dll", press the F4 key, Select "Decode", then press the F5 key, type the address 3DCF1 you just got, come to the beginning of the function we want to change, press the F3 key to edit, then press the "Tab" button, you can Type the assembly code RET 4, then press the F9 key to save, exit the program. Restart the machine, come to DOS, replace the original file to replace the shell32.dll, then restart the machine to enter Windows, try to delete files, How? I can't delete it! Some people will ask, I just want to delete files, I just need to press this method to block the deletefilea function? The answer is not good, starting with the trial is this function, very blame If you press SHIFT DEL to delete files, the file disappears, but press F5 to refresh, the file is coming back, reach the request, but if you delete the file by the recycle station, it is not easy to use. Finally, I chose to intercept the SHFileOperation function. If you really want to stop the file, you can detect the WFUNC parameters in the SHFILEOPSTRUCT structure by writing programs to make the corresponding operation to achieve the effect you want. It is a bit embarrassed.
Always let the system don't delete the file, I think the hard disk space will slowly become small, huh, huh, it is a bit like a virus! In this state, I tried it for an hour, but it's okay, everyone will try it yourself. If you have a problem, don't come to me! :) Finally, we have concluded that this hard mode is good, the benefits are simple, people who know some compilation will understand the whole operation step, the disadvantage is, if the 98 version is different, manual changes are too trouble. And because we just stop the API function, use it within 98, but open 98 DOS window can still delete operation, please pay attention. Here is just a way to take a way, which is the specific use, you will see yourself. DLL disassembly initial
2004-5-15 2:17:52 (Article Category: Programming Foundation)
Ozymandias (original)
I saw some people discussing the anti-assessment of the DLL in the forum. I have helped a friend to analyze a DLL in these days. This DLL is very simple. Now I have analyzed my analysis.
Cheng and everyone share, there is no particularly effective way here, with patience and experience, repeated verification until the call is successful.
There is a DLL2LIB tool, I don't know if I won't use it or have, anyway, I have no success, so I can only rely on myself.
To analyze.
First use tool, IDA / Win32DASM / OLLYDBG
Win32DASM analysis is fast, but the intelligence is not as good as IDA, IDA 2001 development tool runner is definitely not a false name.
It has a very high degree of intelligence, but it identifies common functions, which are tools that are static and negative, and must be dynamically analyzed.
After all, it's hard to find out to analyze it (at least I am like this), of course, you can use S-ICE or TRW, but these tools are limited, TRW is not branched
Hold 2000, once the S-ICE is loaded with only Reboot to cancel the loading, and it has its work in Ring0, so you can only be black, it is very painful.
Bitter, the OLLYDBG selected here is the latest version, supports the trace of the DLL.
The following lists the results of the Win32DASM disassembly:
Exported fn (): getUserNumber - ORD: 0004H: 0040C1B0 55 PUSH EBP: 0040C1B1 8BEC MOV EBP, ESP: 0040C1B3 53 Push EBX: 0040C1B4 56 PUSH ESI: 0040C1B5 57 push EDI: 0040C1B6 8B5D08 MOV EBX, DWORD PTR [EBP 08]: 0040C1B9 33F6 xor ESI, ESI: 0040C1BB 8BC3MOV EAX, EBX: 0040C1BD E846A5FFF Call 00406708: 0040C1C2 6685C0TEST AX, AX: 0040C1C5 7212 JB 0040C1D9: 0040C1C7 40 INC EAX: 0040C1C8 33D2 xor EDX, EDX
* Reference by A (u) Nconditional or (c) ONDITIONAL JUMP AT Address: |: 0040C1D7 (C) |: 0040C1CA 0FB7CAMOVZX ECX, DX: 0040C1CD 0fb60c0B MOVZX ECX, BYTE PTR [EBX ECX]: 0040C1D1 03F1 add ESI, ECX: 0040C1D3 42 inc edx: 0040C1D4 66FFC8 DEC AX: 0040C1D7 75F1 JNE 0040C1CA * Reference by A (u) Nconditional OR (C) ONDITIONAL JUMP ATITY: |: 0040C1C5 (C) |: 0040C1D9 8B450C MOV EAX, DWORD PTR [EBP 0C]: 0040C1DC 8A4012 MOV Al, Byte PTR [EAX 12]: 0040C1DF 3C61 CMP Al, 61: 0040C1E1 720BJB 0040C1EE: 0040C1E3 25FF000000 and Eax, 000000FF: 0040C1E8 6683E861SUB AX 0061: 0040C1EC EB09 JMP 0040C1F7
* Reference by A (u) Nconditional or (c) ONDitional Jump at address: |: 0040C1E1 (C) |: 0040C1EE 25FF000000 and Eax, 000000FF: 0040C1F3 6683E841 SUB AX, 0041
* Reference by a (u) Nconditional or (c) OR (U) |: 0040C1EC (U) |: 0040C1F7 8B550CMOV EDX, DWORD PTR [EBP 0C]: 0040C1FA 8A5213 MOV DL, BYTE PTR [EDX 13]: 0040C1FD 80fa61cmp DL, 61: 0040C200 720CJB 0040C20E: 0040C202 81E2FF000000 and EDX, 000000FF: 0040C208 6683EA61 SUB DX, 0061: 0040C20C EB0AJMP 0040C218
* Referenced by A (u) Nconditional or (c) ONDITIONAL JUMP AT Address: |: 0040C200 (C) |: 0040C20E 81E2FF000000 and EDX, 000000FF: 0040C214 6683EA41SUB DX 0041
* Reference by A (u) Nconditional or (c) ONDITIONAL JUMP AT Address: |: 0040C20C (U) |: 0040C218 0FB7C0 MOVZX EAX, AX: 0040C21B 6BF81A imul edi, Eax, 0000001A: 0040C21E 0FB7C2 MOVZX EAX, DX: 0040C221 03F8 add EDI, EAX: 0040C223 81F74D010000 XOR EDI, 0000014D: 0040C229 83F701 xor EDI, 00000001: 0040C22C 8BC3MOV EAX, EBX: 0040C22E E8D5A4FFFFCALL 00406708: 0040C233 2BF8SUB EDI, EAX: 0040C235 8BC6MOV EAX, ESI: 0040C237 B91A000000 MOV ECX, 0000001A: 0040C23C 99 CDQ: 0040C23D F7F9idiv ECX: 0040C23F 2BFASUB EDI, EDX: 0040C241 8BC7 MOV EAX, EDI: 0040C243 5FPOP EDI: 0040C244 5EPOP ESI: 0040C245 5B POP EBX: 0040C246 5DPOP EBP: 0040C247 C20800 ret 0008 We can know that this function needs two Parameters, through MOV Eax, ESI, we can know that this function is reversed
Value (this is because in the advanced language, it is generally returned by EAX setting function). The specifically returns what type is now there is no way to know, but no matter what
More, we assume that this function is like this:
Int getUserNumber (int A1, INT A2)
After we will gradually, we will slowly fix him, now we start a little analysis.
0040C1B0 55 PUSH EBP: 0040C1B1 8Becmov EBP, ESP: 0040C1B3 53 PUSH EBX: 0040C1B4 56 PUSH ESI: 0040C1B5 57 push EDI This is the Function ProLog, establishing a stack and register save, nothing can be said. : 0040C1B6 8B5D08 MOV EBX, DWORD PTR [EBP 08]: 0040C1B9 33F6 xor ESI, ESI: 0040C1BB 8BC3 MOV EAX, EBX: 0040C1BD E846A5FFFFFCALL 00406708
Here you need to know the parameters passing the function call process, you can go to Asm.Yeah.net to see Luo Yunbin's very good parameters pass and stack repair.
A complex article, simply say, when calling the function, if the parameters are passed through the stack, then the function we discussed may be
Such:
Push a2push a1call getusernumber
At this time, the stack looks like this.
----- A2 ----- a1esp-> ----- ReturnAddress This time you enter the internal PUSH EBP ESP C ----- A2ESP 8 ----- A1ESP 4 - ---- ReturnAddressesp-> ----- EBPMOV EBP, ESP
At this point, addressed A1 can pass EBP 8
: 0040C1B6 8B5D08 MOV EBX, DWORD PTR [EBP 08]; EBX Save First Parameters: 0040C1B9 33F6 xor ESI, ESI: 0040C1BB 8BC3 MOV EAX, EBX: 0040C1BD E846A5FFFFFCALL 00406708
This is very simple ESI cleared, passes the first parameter to Eax, and then call 00406708
So we will go to 00406708 to see: 00406708 89FAMOV EDX, EDI: 0040670A 89C7 MOV EDI, EAX: 0040670C B9FFFFFF MOV ECX, ffffffff: 00406711 30c0xor Al, Al: 00406713 F2 repnz: 00406714 AE SCASB: 00406715 B8Feffffffmov Eax, fffffe: 0040671A 29C8 SUB EAX, ECX: 0040671C 89D7 MOV EDI, EDX: 0040671E C3ret
This is a typical code length code: 00406708 89famov EDX, EDI; Save EDI: 0040670A 89C7MOV EDI, EAX ; EAX is the A1: 0040670C B9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFMOV ECX before call, and the fffffff is set to the maximum 32: 00406711 30C0 xor Al, AL; Al clear zero
We know the string operation of assembly instructions generally passed ESI and EDI, the above process is given in the comment: 00406714 F2repnz: 00406714 AE SCASB; Judge whether the string ends: 00406715 B8Fefffffffmov Eax, fffffe: 0040671A 29C8 SUB EAX, ECX; EAX saves the string length: 0040671C 89D7MOV EDI, EDX; Restore EDI: 0040671E C3ret
The above analysis we know that the parameter A1 is a string, and now fix our function as follows Int getUserNumber (Char * A1, INT A2)
Continue our analysis:
: 0040C1C2 6685C0TEST AX, AX; Whether the length is zero: 0040C1C5 7212 JB 0040C1D9; zero jump: 0040C1C7 40 INC EAX; EAX plus one: 0040C1C8 33D2 xor EDX, EDX; EDX Clear
We use the C language to write equivalent programs as follows: int GetUserNumber (Char * strusername, Test * Pt) {
ESI = 0;
INT LEN = Strlen (StruserName); if (len <= 0) GOTO _SKIP_USERNAME;
_SKIP_USERNAME:
}
Continue analysis and further correct our code
* Reference by A (u) Nconditional or (c) ONDITIONAL JUMP AT Address: |: 0040C1D7 (C) |: 0040C1CA 0fb7camovzx ECX, DX; ECX 零 零: 0040C1CD 0FB60C0B MOVZX ECX, BYTE PTR [EBX ECX] ; EBX Save First Parameters: 0040C1D1 03F1Add ESI, ECX; Remove Strings ECX bit : 0040C1D3 42INC EDX; EDX plus one: 0040C1D4 66ffc8 DEC AX; AX string length minus one: 0040C1D7 75f1jne 0040c1ca ; String is not processed, continued above is a typical base add-in addressing mode, very simple, equivalent C code as follows: int GetUserNumber (char * StruserName, Test * Pt) {
ESI = 0;
INT LEN = Strlen (StruserName); if (len <= 0) GOTO _SKIP_USERNAME;
For (int i = 0; i _SKIP_USERNAME: } Continue analysis and further correct our code * Reference by A (u) Nconditional or (c) OONDitional Jump at address: |: 0040C1C5 (C) |: 0040C1D9 8B450CMOV EAX, DWORD PTR [EBP 0C]; take the second Parameters: 0040C1DC 8A4012 MOV Al, Byte PTR [EAX 12]; mobile 0x12 = 18 bytes: 0040C1DF 3C61cmp Al, 61 And 0x61 = 'a' comparison: 0040C1E1 720BJB 0040C1EE; less than jump: 0040C1E3 25FF000000 and EAX, 000000FF; Reserved Eax low 8 Bit: 0040C1E8 6683E861 SUB AX, 0061 ; calculation and 'a' gap: 0040C1EC EB09 JMP 0040C1F7; Jump to 0040C1F7 It can be seen that the string length indicated by the first parameter is 0, it will jump directly here. The problem here is how we know the type of the second parameter? The answer is no way, because now this information, we have no way to know what type of the second parameter is, but must be a memory area. Domain, because MOV Al, Byte PTR [EAX 12] tells us, now let us simulate this area We define a structure to simulate, in fact, when we write the program, if the parameter type does not match when the function is called, it will get compiled error. In fact, this error is given by the compiler. He has nothing to do with we can successfully call the function, because if the type really does not match, it will be run Wrong, so our parameter type is not necessarily the same as the actual DLL original code, but must be compatible with the actual DLL original code. So I use the structure to simulate and will not destroy the generality of the issues we discussed. Define the following structure: Struct Test {cha C18_UNUSED [18]; CHAR C19;}; now re-correcting our function int GetUserNumber (Char * strusername, Test * Pt) {Int ESI; char al; ESI = 0; INT LEN = Strlen (StruserName); if (len <= 0) GOTO _SKIP_USERNAME; For (int i = 0; i _SKIP_USERNAME: Al = Pt-> C19_ISNUMBER; if (Al <'a') // Judgment Character Size GOTO Islower; } Continue analysis * Reference by A (u) Nconditional or (c) ONDITIONAL JUMP ATITY: |: 0040C1E1 (C) |: 0040C1EE 25FF000000 AND EAX, 000000FF; CMP Al, 61 will jump here EAX reserves 8 bits: 0040C1F3 6683E841 SUB AX, 0041 ; 0x41 = 'a', calculation and 'a' gap * Reference by A (u) Nconditional or (c) ONDITIONAL JUMP AT Address: |: 0040C1EC (U) |: 0040C1F7 8B550CMOV EDX, DWORD PTR [EBP 0C]; EDX Save Two parameters: 0040C1FA 8A5213 MOV DL, BYTE PTR [EDX 13] ; Take 0x13 = 19 bits: 0040C1FD 80fa61cmp DL, 61: 0040C200 720CJB 0040C20E: 0040C202 81E2FF000000 and EDX, 000000FF: 0040C208 6683EA61 SUB DX, 0061: 0040C20C EB0A JMP 0040C218 The above section is almost the same as the code above, does not make an analysis. It is worth mentioning that we need to fix the structure we defined in front and correct: Struct Test {char C18_UNUSED [18]; char C19; CHAR C20}; Equivalent C code INT ESI; char al; char DL; int EdX; int EDI; int Eax; int ECX; ESI = 0; INT LEN = Strlen (StruserName); if (len <= 0) GOTO _SKIP_USERNAME; For (int i = 0; i _SKIP_USERNAME: Al = Pt-> C19_ISNUMBER; if (al <'a') // Judgment Character case GOTO ISNUMBER1; Al - = 'a'; goto _Continue1; ISNumber1: Al - = 'a'; _Continue1: DL = Pt-> C20_isNumber; if (DL <'a') // Judgment Character Size GOTO ISNUMBER2; DL - = 'a'; goto _continue2; isnumber2: DL - = 'a'; } Our goals are coming, the last code * Reference by A (u) Nconditional or (c) ONDITIONAL JUMP ATIT: |: 0040C20C (U) |: 0040C218 0FB7C0 MOVZX EAX, AX: 0040C21B 6BF81AIMUL EDI, EAX, 0000001A: 0040C21E 0FB7C2 MOVZX EAX, DX: 0040C221 03F8 add edi , EAX: 0040C223 81F74D010000 XOR EDI, 0000014D: 0040C229 83F701 xor EDI, 00000001: 0040C22C 8BC3MOV EAX, EBX First parameter: 0040C22E E8D5A4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFECALL 00406708 ; the length of the previous analysis: 0040C233 2BF8 SUB EDI, EAX; minus the length value: 0040C235 8bc6mov Eax, ESI; ESI is the first parameter ASC code and: 0040C237 b91a000000 MOV ECX, 0000001A; ECX = 0x1a = 26: 0040C23C 99 CDQ; EAX extension into edx: EAX: 0040C23D F7f9idiv ECX; divided by ECX = 26: 0040C23F 2BFA SUB EDI, EDX ; minus the remainder: 0040C241 8BC7 MOV EAX, EDI; pass to Eax: 0040C243 5F POP EDI: 0040C244 5EPOP ESI: 0040C245 5BPOP EBX: 0040C246 5DPOP EBP: 0040C247 C20800 ret 0008 This code is also very simple, here we get approximation C source code, here I have not implemented for the function completed by the CDQ instruction, but this pair No effect: int GetUserNumber (Test * Pt) {Int ESI; CHAR Al; CHAR DL; Int EDX; INT EDI; Int Eax; int ECX; ESI = 0; INT LEN = Strlen (StruserName); if (len <= 0) GOTO _SKIP_USERNAME; For (int i = 0; i _SKIP_USERNAME: Al = Pt-> C19_ISNUMBER; if (al <'a') // Judgment Character case GOTO ISNUMBER1; Al - = 'a'; goto _Continue1; ISNumber1: Al - = 'a'; _Continue1: DL = Pt-> C20_isNumber; if (DL <'a') // Judgment Character Size GOTO ISNUMBER2; DL - = 'a'; goto _Continue2; ISNumber2: DL - = 'a'; _ Continue2: EDI = Al * 0x1a; // 26eax = DL; EDI = EAX; EDI ^ = 0x14d; EDI ^ = 0x1; EDI - = LEN; EAX = ESI; ECX = 0x1a; // 26 // Edx = EAX symbol bit expansion EDX = EAX% ECX; EAX / = ECX; EDI - = EDX; EAX = EDI; Return Eax;} It's ending here, what I want to say is that the function of the analysis is relatively simple, does not have a generality, involving more complex functions, such as Virtual function, class analysis, here my analysis is not technically, just some simple DLL functions, give me some Experience, I am honored to you, I am sorry for you, I am sorry for you, I hope you don't marry me. "Variable speed gear" research Note: If you read this article, you are interested in our software, please go to our homepage www.vrbrothers.com. Note: In order to save space, this article is directly used by some computer terms without a detailed explanation. If the reader is unfamiliar, it is recommended to refer to Tsinghua University Press, Zhou Mingde's "Microcomputer System Principles and Application" The corresponding chapter on the 8253/8254 timer and X86 protection mode. Maybe I am ignoring, saying that you are not afraid of you, for the famous software like "shifting gears", I have been five days ago, that is, February 28, 2001, I heard it. I have a few students like to play graphic MUD. I have seen "mud" technology together all day. I didn't have much interest in MUD itself, but I happened to listen to them that morning, I said that a MUD site is clearly used. It is strictly forbidden to use "gears", which is curious about what they are "gears". Others tell me, "Gear" is a software that accelerates the game under Windows, they rely on this software for cheating when playing MUD. This is not banned to let me breath, let the Windows game change speed, amazing! I have always been very interested in technology, I have heard that there is such a magical software, of course, I want to think about it. This software does not complicate, I originally thought that it was a good self-study, but I thought of several lessons, I have never collected. It is also ingenious, and our semester has a must-have a couch is a Linux kernel analysis. In the past few days, he just learned the process schedule. The teacher said that when a clock is interrupted, the operating system should do a lot of things, such as retreat if necessary. The scheduling process is to achieve a multi-task, but also update the system clock ... Slow, I am very dedication, if the clock is broken faster, what happens? We have learned the course of "Microcomputer Principles", I know that it is more difficult to make clock breaks, I used to write such a program in the assembly language under DOS, which is our job. But I used to run under Windows, but I can't accelerate the Windows system. It is clear that Windows 9X is compatible with the X86 virtual machine. My program can only change the virtual machine, that is the black The clock interruption of the window. So I tried to move the previous DOS program to the 32-bit environment. It is appropriate to use VC embedding to do this, but add __asm in a VC program framework, and then use the previous assembler to put it in. I am full of hoping monsters, as a result, a "the program implemented illegal operation", my experiment, ended. Later, calm down, think about it, this failure is obvious. Windows acts as a complex 32-bit operating system, if you let you operate hardware, then you can't run a few programs. But how do you bypass the operating system to operate hardware? I first thought of VXD, write a driver, I definitely manipulate hardware, but it is a pity that I will not design a driver. So I thought of the source code of the CIH that I saw. CIH didn't write VXD, but I can operate hardware to burn the BIOS. Chen Yinghao is too great. His procedure is exquisite. I have remembered. So I imitated his technology, modify the IDT table, create an interrupt door, then an interrupt, enter Ring0, now I can do anything, in the previous DOS program, write a control word in the 8253 timer, and then divide Two new clock interruptions occur frequent frequency, everything goes well! (For detailed technology, please refer to my "Brothers" source code) I see the cursor of the VC editing area crazy flashing; double-click has been invalid, because Windows thinks that I double-click the time interval too long; Windows taskbar right is fast I have already said that I have succeeded. At the time, I thought of the principle of "shifting gear", but when I copied the "gear" from the classmate and studied, I found that Windows clock did not change, and the game speed can be added, that is, said , "Gear" uses different technologies that are different from my procedures, what technology is it? I decided to continue research. I visited the "shifting gear" home page. There is a section "You ask me" on this homepage. Mr. Wang Rong, who is "gear", is conducting technical support. I have tried to find some technical details about "gears", but it is a pity that I didn't find that Mr. Wang Rong just told everyone that this program cannot be written in VB and other problems. It is not easy to see a foreign country. People can not publish source code, in fact, this is also what I want to ask, but Mr. Wang Rong clearly said that this is not banned. I also want to write to the original code, maybe he does not announce to foreigners, and the Chinese may not necessarily. But our "stinky old nine" loves a face, I really can't ask. At this time, it was already 10 o'clock in the evening, I decided to sacrifice Softice, study his procedure with one night. The tools used at the time were Softice, WD32ASM, and VC. Two reference books were the "microcomputer system principle and application" and "Linux operating system kernel analysis" (all our textbooks, huh, huh). At first, a file called hook.dll version of "Variable Speed Gear" 0.2 version has greatly attracted my attention, I doubt that he uses the Windows message hook to speed, the message hook, I am very familiar, but I put the MSDN About hooks The introduction has been seen for a long time, nor did it come and change it and change. At this time, I looked at the "Variable Speed Gear" version 0.1 obtained on Mr. Wang Rong. Only did not have this document in the old version, also That is, I only need to disassemble his main program, so I don't say that I will be dismantled by WD32ASM first, and the code code is more than 5,000, it is not much. I am from the import function of this program. It is used for Timing for Timer, TimegetTime, TimeSetEvent, and see where they are quoted. I found that these functions have appeared, and most In this form: * Reference to: Winmm.TimegetTime, Ord: 0098H: 00401F3E 8B0D64424000 MOV ECX, DWORD PTR [00401F44 8B11 MOV EDX, DWORD PTR [ECX] That is, he does not call these functions, just obtain the entry address of the function, saved in the ECX, and then gets the previous byte of the function according to this entry address, saved in the EDX. This makes me think of the principle of the Hook API discussed above 9CBS and others. At the time, I also requested a hook API routine. If I want hook, I want TimegetTime, modify the address in ECX or modify EDX. Several heads of the heads are in line, write with assembly language, similar to this code seen above. In order to test the "gear", it is a TimegetTime who wants to hook. I wrote a very simple applet, call TimegetTime, and display a number every second. After acceleration with "gears", it really shows more speed. Follow this TimegetTime function with Softice, the first instruction becomes a jump, which fully illustrates that "gears" really hook these APIs, it is not difficult to guess, he wants to change the return value of the function, that is, in TimegetTime At the end, I also jumped into the "gear" itself, patience and followed, I found it back to the TimegetTime hit, so that when TimeGetTime returned, first returned "Gear" code first ( This thought is indeed very clever), and the return value has jumped back to my app after processing. As for how to deal with this return value, it is simple, changed to the original twice, and the application speed has increased by 2 times. Looking back and then watching the WD32ASM disassembled code, I found that the SGDT command and two SLDT instructions in front of the Hook API, which is the unique directive of the x86 protection mode for obtaining a global descriptor table, further get Local descriptor table, this code has caused my interest, followed by Softice, take a few steps down, and guess it, roughly organize such ideas: 1. Create a memory mapping, map your code to where you are 0x80000000, under Win9x, this virtual memory is shared by all processes. 2. First get the address of the local descriptor table, then use this table to modify the privilege level of the code segment. 3. Create a call door with the local descriptor table, and enter RING0 in X86 must be performed by the door. CiH is done with the interrupt door, where the callimeter is completed, and the same intersection is used. 4. Save the first six bytes of several key functions, change to a jump instruction, jump to the code that has been mapped to the high-end. 5. When a function call is invoked, enter its own code, and enter the Ring0 through the call gate, the return value is changed. It was already 5 o'clock in the morning. Since the main thoughts have been mastered, I have not seen this code, and I have to go to class at 8 o'clock and go to sleep. Looking back, I think that Mr. Wang Rong's code is worth a scrutiny: 1. If you want hook API, be sure to change the first instruction of the function? If you only change the entry address of the function, isn't it easy to compile? 2. Even if you want to change the first instruction of the function, be sure to enter RING0? 3. Even if you want to enter Ring0, use the interrupt door not more convenient than using the calling door? Of course, according to Mr. Wang Rong's statement on his homepage, "Variable Speed Gear" 0.1 is he written in 1997 three years ago. At that time, Windows95 had just come out for two years, and there is such a technology that it is difficult, here I am sincere admiration to Mr. Wang Rong's drilling spirit. Three days after I studied the principle of "shifting gears", I used my original research results as the core, wrote the original version of "Brother Transmission", and the technology of "shifting gears" is because I think my technology is more. Superior, let alone, there is no ticking to teeth, ^ _ ^ Finally, I would like to thank Mr. Wang Rong, so wonderful ideas worthy of our admiration. "Variable speed gear" re-study Lift the "shifting gear" (hereinafter referred to as "gear") this software, everyone should know, the software is known as the world's first programs that can change the game speed. I am very magical when I started, I can't think of the principle of achieving it, but I have a limited personal level. I have never been able to solve it. It has become a big question mark that I can't stay in my brain. I saw a article called "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " However, there is still a relatively vague understanding: the original gear is achieved by cutting the game program for the time-related function call and modify the return result. In order to completely understand the principle of the gear, I am going to have an export. Taking into account the "hand" author from the "gear" disassembly code, then I also start from the disassembly code. However, it is not enough to compile the content, and a few books from the library have a number of books on the underlying mechanism of Windows and 386. After almost two weeks of "practice", the self-feeling is a bit good, haha, I also have something to wait. Put the "gear" out of eight pieces! Before I started, I saw "Issue" again. This time you can clearly: Jump to the Ring0 class section by calling the door, modify the first 8 bytes of each system time-related function as JMP instructions, and turn To the "gear" mapped to the code above 2G, the purpose of intercepting the call to each system time-related function. But at the same time, my doubts are also more clear: 1. "Gear" how to establish a calling door descriptor pointing to the code that maps to 2G or more; 2. How to map your code to a linear address of 2G 3. How is the code that mapped to 2G to do this with such doubts correctly in the case of code base, I officially started an analysis of "gears" disassembly code. Tools, don't say, of course, Softice for Windows98, W32DASM, OK, departure! My "Gear" version is 0.221 for Win98 and WinMe, with two files (shifting gears. EXE and HOOK.DLL). First look at the hook.dll, use W32DASM to disassemble hook.dll, look at its output function: ? ghwnd @@ 3pauhwnd __ @@ a? GNHOTKEY1 @@ 3ka? GNHOTKEY2 @@ 3ka? GNHOTKEY3 @@ 3ka? gnhotkey4 @@ 3ka? nhook @@ 3ha? setHook @@ yahpauhwnd __ @@@ z? unhook @@ yahxz Look at the function name, if the DLL is just installing the hook captures the speed button, it is not too big to do with my research purposes, jumps! Look at the change in the transmission gear. EXE import function, TimegetTim, getTickcount and other functions are in it. Hey, there is CreateFileMappinga and MapViewOffileEx, it seems that "gears" use these two functions to create mapping files. Several key import functions are listed below: Hook.?gnHotKey1@@3KA Hook.?gnHotKey2@@3KA Hook.?gnHotKey3@@3KA Hook.?gnHotKey4@@3KA Hook.?SetHook@@YAHPAUHWND__@@@Z KERNEL32.CreateFileMappingA KERNEL32.GetModuleFileNameA KERNEL32.GetModuleHandleA KERNEL32. GetTickCount kernel32.mapviewoffileex kernel32.QueryperFormanceCounte user32.killtimer user32.sendMessagea user32.settimer Winmm.TimegetTime Winmm.TimeSetEvent Since the "gear" intercepted TimegetTime, then I will track the implementation of the TimegetTime function. I first wrote a Win32 app (hereinafter referred to as app), when the TimegetTime is called when the client is left, and the returned result is output to the client area. Run this program, open the "gear", change the current speed. Ctrl D exhaled Softice, BPX TimegetTime, exit, left the APP client area, and Softice jumped out. Ha, the first instruction of the TimegetTime function is JMP 8xxx 002a, and F8 continues to execute, and enter the "gear" map to the code above 2G linear addresses. All the way f8, found that "Gear" will then restore the TimegetTime command, and call TimeGetTime again so that the correct result of TimegetTime is obtained and saved. "Gear" will change the TimegetTime command to JMP 8xxx 002a. I guess what I have to do next! That's right, return the return value to the Return value to the program app to call TimegetTime. I carefully analyze, the formula of "gear" modification return value is as follows: multiple * (return value - the return value of the first call TimegetTime) Modified return value = ----------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- " The return value after the last revised "is the unconfirmed that I guess, for reference only. The code analysis has been part, but I have not resolved before, how is the "gear" mapped by the code? Also get the right to modify the code? Since CREATEFILEMAPPINGA is called in the "gear", I want to install the call door, the initialization portion of the mapping code should be in the vicinity of the function code. Ok, along this idea, exhale Softice, set breakpoints at Createf Ilemappinga, turn the "gear" and then run. SoftICE jumps out, stopping at CreateFile Mappinga, F11 returns to the code of "gear". See the form of "gears" call CreateFileMappinga as follows: CreateFilemappingA (FF, 0, 4, 0, 10000, 0); Visible "Gear" creates a mapping file with a length of 0x10000, continues, "gear" then calls MapViewOffileEx, call the form as follows: MapViewOffileEx (EDX, 2, 0, 0, 0, EAX); // EDX The mapping file handle // EAX returned for CreateFilemappingA is the base address of the application mapping code, and Eax is 0x8000 0000 when the first call is called. Here is the key, "gear" is mapped to the memory space of the base address to 0x8000 0000, and it is not seen that Windows really allows it to map? Sure enough, "gear" judges whether the return value is valid after the call, if it is invalid, adds the base address of the last application to 0x1000, and then calls MapViewOffileEx again. It is looped to success until it is successful, and the returned address will be saved. Next, "Gear" copies the code lines of the original "gear" EXE to the mapping area. At this point, the "gear" has mapped the critical code to the linear address of 2G. I will f8, haha, and the familiar SGDT command has played a photo. "Gear" Save the Global Descriptive Table Linear Address, and then save the local descriptor table index with the SLDT command to calculate the LDT base address. Then, "Gear" creates a code segment of the privilege level in the local descriptor to point to the "gear" own code that needs to use Ring0 privileges, and points the address of the call gate pointing in the local descriptor table 2. Change to "gear" is mapped to code higher than 2G. Then "gear" calls each time-related API and saves its return value to leave the result of the result. The "gear" is called again to modify the first command of each API with a code that mapped to 2G. In the beginning of the "gear", the "gear" is over, just waiting to be hooked on the game in the drum, haha! The end code is just a matter of recovery, it is just the inverse process of the initialization code, so it will not be described again (in fact, I am too lazy to see, ^ _ ^!). So, my acceleration principle of "gears" has been There is a general understanding, deeply feeling the exquisiteness of the "gear" code, so I feel that there is a summary of some of the techniques used in the "gear": 1. The base address is not related to the code, and the above is a title, ^ _ ^. Looking at the initialization code of the "gear", knowing that the base address of its mapping code is almost random, how is the "gear" guarantee that the code after the map can run properly? If the code is a complete order, it has nothing, but if you want to call the subroutine in your mapped code? Oh, just calculate the entry address of the child program and call it, but still to get the address where the map code is located. The "gear" simply uses two instructions to get the address of the instruction currently executed, specifically (address is assumed): 0: 0 Call 5 0: 5 POP ESI Now the value in the ESI is 5, haha! The CALL here is close-in, the whole command is E800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000-00-00 Address). 2. Modify the call door, generate JMP instructions, and modify the code is highly dependent on the CPU operation, the skill is also very strong, mainly to drill the vulnerability of the operating system. For example, "Gear" is to use SGDT, SLDT to obtain global and local descriptor table base sites to install call doors. By accessing the calling door to get RING0 permissions for some operations allowed by the system; and CIH viruses are interrupted with SIDT Description The Chart At the base address The interrupt gate is installed and then the soft interrupt is obtained, the principle is the same. These are discussing many times on the water, everyone is very familiar, so they don't dare to go to the ax, it is written. 3.64K Code Writing by calling createFileMappinga function parameters can know "gear" only maps 10000 (64K) area, so that the code and data mapped above 2G will never be greater than 64K. I think the author chooses 64K to the size of the map area, which may be related to the caller or data. After any one of the mapping code, it obtains a base address of the mapping code after obtaining the current command address, and then the offset of the subroutine inlet or data can be obtained. my comment: In a word: Mr. Wang Rong, who admires "gears". The "gear" code shows that his deep understanding of the Windows running mechanism and the thick compilation of the idea. For me, "gears" seem to be a beautiful art. Every place is worthwhile, so I have seen my analysis process after I have seen the "gear" code. impulse. But at the same time, I have to admit that the implementation of the "gear" is realized by its highly technically skill, in other words, this is the limitations of this method. Isn't it the interception of the API? Is it so troublesome? In order to confirm your own ideas, I directly found a hook API code on CodeGuru, which is the input festival of modifying the process PE image in all DLL processes by installing the WH_CBT type global hook. Methods have a detailed description in "Windows Core Programming"). Make the code a little modification, you can work (tried under the StarCraft, you can change the game speed). Despite the only 98, I feel that I can use it in 2000 because I only use one or two compilation instructions in the code, and the entire program is running under RING3, and there is no derailed move. Of course, this method also has a disadvantage that the API call does not work with loadLibrary to get the WinMM.dll and get the TimegetTime address with GetProcAddress (why the reason is in "Windows Core Programming"). I am planning to publish the source code after the test program is slightly perfect, and you will be welcome to download. My gratitude: After I completely figure out the code of "Gear", it is already the third day of the morning, helplessness is too much, and it is not like "notes", I only spend a night, I will spend it. One morning, two afternoons, two nights ended the battle, it is really embarrassing. I have been able to adhere to myself for two days, it is not open to Xiaoqiang's support with the brothers of the bedroom. I didn't know how much smoke in these days. I didn't think of the news. I only said that I am here! Also I would like to thank Sunlie to read this article very much, pointing out the mistakes in the original text and very valuable comments! The last thing to say is that personal level is limited, and there is a mistake in the article. Welcome everyone! ^ _ ^ Addition A: Softice for Windows98, W32DASM, Visualc 6.0 operating system: Window98 2nd analysis goal: Variable speed gear for 98me version: 0.221 Reference book or article: 80x86 assembly language program design tutorial Yang Jiwen, etc. WINDOWS analysis - Initialization and Nuclear Articles Tsinghua University Press Virtual Equipment Driver Development Intel 32-Bit System Software Programming 80x86 Instruction Reference Manual "" Transmission Gears "Research Book" Annex B: "gear" the key code fully commented an initialization section (Start analysis "gear" call CreateFileMappingA function) 0167: 00401B0E PUSH 00 0167: 00401B10 PUSH 00010000 0167: 00401B15 PUSH 00 0167: 00401B17 PUSH 04 0167: 00401B19 PUSH 00 0167: 00401B1B PUSH FF 0167: 00401B1D CALL [Kernel32! CreateFilemappinga]; CreateFileMappingA; call form, right: CreateFileMappingA (FF, 0, 4, 0, 10000, 0) 0167: 00401B23 MOV ECX, [EBP-30] 0167: 00401B26 MOV [ECX 00000368], EAX 0167: 00401B2C MOV DWORD PTR [EBP-14], 800000 0167: 00401B33 JMP 00401B41 0167: 00401B35 MOV EDX, [EBP-14] 0167: 00401B38 Add EDX, 00010000; Application Base Add 0x10000 0167: 00401B3E MOV [EBP-14], EDX 0167: 00401B41 MOV EAX, [EBP-14] 0167: 00401B44 PUSH EAX Mapping file base 0167: 00401B45 push 00; mapping bytes 0167: 00401B47 PUSH 00; file offset low 32 bits 0167: 00401B49 push 00; file offset high 32 bits 0167: 00401B4B PUSH 02; Access mode 0167: 00401B4D MOV ECX, [EBP-30] 0167: 00401B50 MOV EDX, [ECX 00000368] 0167: 00401B56 PUSH EDX; CreateFileMappingA mapping file handle returned 0167: 00401B57 cALL [KERNEL32 MapViewOfFileEx!]; call of the form at right: MapViewOfFileEx (EDX , 2, 0, 0, 0, EAX 0167: 00401B5D MOV ECX, [EBP-30]; [EBP-30] for the upcoming map to 2G 0167: 00401B60 MOV [ECX 0000036C], ECX; The start address of the code 0167: 00401B66 MOV EDX, [EBP-30] 0167: 00401B69 CMP DWORD PTR [EDX 0000036C], 00; Check MapViewOffileEx 0167: 00401B70 JZ 00401B74; Return value, if 0 continues tone 0167: 00401B72 JMP 00401B76; call MapViewOfFileEx 0167: 00401B74 JMP 00401B35; until it succeeds 0167: 00401B76 MOV EAX, [EBP-30] 0167: 00401B79 MOV ECX, [EAX 0000036C] 0167: 00401B7F MOV [EBP-08], ECX; mapping file start address deposit [EBP-08] 0167: 00401B82 Call [Winmm! TimegetTime] 0167: 00401B88 MOV [EBP-14], EAX; TimegetTime 0167: 00401BA0 MOV ECX, [EBP-08] The return value is saved to [EBP-14] 0167: 00401BA3 MOV EDX, [EBP-14]; and mapping file base 4 FF30 0167: 00401BA6 MOV [ECX 0000FF30], EDX ... omitted code Similar Save the call for the initial GetTickCount, QueryPerformanceCounTer return value 0167: 00401bed MOV DWORD PTR [EBP-14], 00000000 0167: 00401BF4 MOV EDX, [EBP-30] 0167: 00401BF7 MOV EAX, [EDX 0000036C] 0167: 00401BFD MOV ECX, [EBP-14] 0167: 00401C00 MOV BYTE PTR [ECX EAX 0000F000], 9A; 9A is a long-conditioned instruction code 0167: 00401c08 MOV EDX, [EBP-14] 0167: 00401C0B Add EDX, 01 0167: 00401C0E MOV [EBP-14], EDX 0167: 00401C11 MOV EAX, [EBP-14] 0167: 00401C14 Add Eax, 04 0167: 00401C17 MOV [EBP-14], EAX 0167: 00401C1A MOV ECX, [EBP-30] 0167: 00401C1D MOV EDX, [ECX 0000036C] 0167: 00401C23 MOV EAX, [EBP-14] 0167: 00401C26 MOV BYTE PTR [EAX EDX 0000F000], 14; 14 is an index of the calling door descriptor 0167: 00401C2E MOV ECX, [EBP-14] 0167: 00401C31 ADD ECX, 01 0167: 00401C34 MOV [EBP-14], ECX 0167: 00401C37 MOV EDX, [EBP-30] 0167: 00401C3A MOV EAX, [EDX 0000036C] 0167: 00401C40 MOV ECX, [EBP-14] 0167 : 00401C43 MOV BYTE PTR [ECX EAX 0000F000], 00; Call instructions other parts 0167: 00401C4B MOV EDX, [EBP-14] 0167: 00401C4E Add EDX, 01 0167: 00401C51 MOV [EBP-14], EDX 0167: 00401C54 MOV EAX, [EBP-30] 0167: 00401C57 MOV ECX, [EAX 0000036C] 0167: 00401C5D MOV EDX, [EBP-14] 0167: 00401C60 MOV BYTE PTR [EDX ECX 0000F000], C2 0167: 00401C68 MOV EAX [EBP-14] 0167: 00401C6B Add Eax, 01 0167: 00401C6E MOV [EBP-14], EAX 0167: 00401C71 MOV ECX, [EBP-30] 0167: 00401C74 MOV EDX, [ECX 0000036C] 0167: 00401C7A MOV EAX, [EBP-14] 0167: 00401C7D MOV BYTE PTR [EAX EDX 0000F000], 00 0167: 00401C85 MOV ECX, [EBP-14] 0167: 00401C88 Add ECX, 01 0167: 00401C8B MOV [EBP-14], ECX 0167: 00401C8E MOV EDX, [EBP-30] 0167: 00401C91 MOV EAX, [EDX 0000036C] 0167: 00401C97 MOV ECX, [EBP-14] 0167: 00401C9A MOV BYTE PTR [ECX EAX 0000F000], 00 0167: 00401CA2 MOV EDX, [EBP-14]; The above code is at the mapping code offset F000 Write instruction call 0014: 0000 0167: 00401CA5 Add EDX, 01; Directive A91400C20000 Total 6 bytes 0167: 00401CA8 MOV [EBP-14], EDX; 0167: 00401CAB MOV ESI, 0040213B; start address of the code to be copied 0167: 00401CB0 MOV EDI, [EBP-08]; To copy the target address of the code (mapping area) 0167: 00401CB3 MOV ECX, 00402688; 402688 is the end address of the code to be copied 0167: 00401cb8 SUB ECX, ESI 0167: 00401CBA REPZ MOVSB; copy all the code to the mapping area 0167: 00401CBC SGDT FWORD PTR [EBP-1C]; This sentence is very critical 0167: 00401cc0 Lea EAX, [EBP-001C] 0167: 00401cc6 MOV EAX, [EAX 02 ]; Take GDT linear base 0167: 00401cc9 xor EBX, EBX 0167: 00401ccb SLDT BX; take LDT in G Offset 0167: 00401CCE and BX, -08 0167: 00401CD2 Add Eax, EBX 0167: 00401CD4 MOV ECX, [EAX 02] 0167: 00401CD7 SHL ECX, 08 0167: 00401CDA MOV CL, [EAX 07] 0167 : 00401CDD ROR ECX, 08; The above calculates the LDT linear base 0167: 00401CE0 MOV [EBP-0C], ECX; saving 0167: 00401CE3 MOV EAX, [EBP-30] 0167: 00401CE6 MOV ECX, [EBP-0C] 0167 : 00401CE9 MOV [EAX 00000370], ECX 0167: 00401CEF MOV EDX, [EBP-30] 0167: 00401CF2 MOV EAX, [EDX 0000036C] 0167: 00401CF8 MOV ECX, [EBP-0C] 0167: 00401CFB MOV [ECX; Save the LDT linear base to map code 0167: 00401d01 MOV AX, CS; get the current code segment description symbol 0167 : 00401D04 and AX, FFF8 0167: 00401D08 MOV [EBP-10], AX 0167: 00401D0C MOV EDX, [EBP-10] 0167: 00401d0f and EDX, 0000FFFF; EDX is the offset of code segment descriptor in LDT 0167 : 00401D15 MOV EAX, [EBP-30] 0167: 00401d18 MOV ECX, [EAX 00000370]; ECX is LDT linear base 0167: 00401D1E MOV EAX, [EBP-30] 0167: 00401D21 MOV Eax, [EAX 00000370]; EAX is the LDT linear base address 0167: 00401D27 MOV ESI, [EDX ECX] 0167: 00401D2A MOV [ES 08], ESI 0167: 00401D2D MOV ECX, [EDX ECX 04]; Copy the current code segment descriptor to 0167: 00401D31 MOV [ EAX 0C], ECX; LDT 1 item 0167: 00401D34 MOV EDX, [EBP-30] 0167: 00401D37 MOV EAX, [EDX 00000370] 0167: 00401D3D MOV CL, [EAX 0D] 0167: 00401D40 and Cl, 9F 0167: 00401D43 MOV EDX, [EBP-30] 0167: 00401D46 MOV Eax, [EDX 00000370] 0167: 00401D4C MOV [EAX 0D], Cl; modify the DPL of the LDT 1 item, then the call When the door is transferred to this code, I get RING0 permissions 0167: 00401D4F MOV EAX, [EBP-0C] 0167: 00401D52 Add Eax, 10; NOTE 2-in-LDT index 2 call doors address 0167: 00401d55 MOV EBX, 0040213B 0167: 00401D5A MOV [EAX], EBX 0167: 00401D5C MOV [EAX 04], EBX 0167: 00401D5F MOV W ORD PTR [EAX 02], 000c 0167: 00401d65 MOV Word PTR [EAX 04], EC00; Turnover Door Modifications 0167: 00401D6B MOV ECX, [EBP-08] 0167: 00401D6E MOV EDX, [WINMM! TIMEGETTIME] 0167 : 00401D74 MOV [ECX 0000fee0] ; EDX; save partially omitted timeGetTime entry address ... are sequentially stored GetTickCount, GetMessageTime, timeSetEvent, SetTimer, timeGetSystemTime, QueryPerformanceCounter entry address 0167: 00401DD2 MOV ECX, [EBP-08] 0167: 00401DD5 MOV EAX, [WINMM timeGetTime!] 0167 : 00401DDA MOV EBX, [EAX] 0167: 00401DDC MOV [ECX 0000fe40], EBX 0167: 00401DE2 MOV EBX, [EAX 04] 0167: 00401DE5 MOV [ECX 0000fe44], EBX; save the TimegetTime function 8 bytes ... sequentially stored instruction portion omitted GetTickCount, GetMessageTime, timeSetEvent, timeGetSystemTime, before QueryPerformanceCounter 8 bytes of the instruction 0167: 00401E6D MOV bYTE PTR [ECX 0000FE90], E9 0167: 00401E74 MOV EAX, 00402165 0167: 00401E79 SUB EAX, 0040213B Eax is the offset of the code in the mapping code 0167: 00401e7e Add Eax, ECX; calculates the linear entrance address of the intercept code 0167: 00401e80 SUB Eax, [WinMM! Timeget Time] 0167: 00401E86 SUB EAX, 05; JMP command length 5 bytes 0167: 00401e89 MOV [ECX 0000fe91], EAX; calculation generated JMP instruction from TimegetTime jumps to the intercept code and saves ... The omission part is calculated in turn generating GetTickCount, GetMessageTime, timeSetEvent, timeGetSystemTime, QueryPerformanceCounter jump instruction JMP intercepted code and save 0167: 00401F58 CLI; interrupt disabled, to guard against accidents when modifying the code 0167 occurs: 00401F59 MOV EAX, 004021F3; 0167: 00401F5E SUB EAX, 0040213B; calculated The offset of the subroutine in the mapping code 0167: 00401f63 add Eax, [EBP-08]; EAX = 8xxx 00b8 0167: 00401f66 push EAX; incoming parameter Eax is modified to modify the TimegetTime code; Subroutine entry address 0167: 00401F67 MOV EAX, [EBP-08]; call 8xxx 0000 0167: 00401F6A CALL EAX; timeGetTime first return instruction is omitted portion sequentially changed ... modified GetTickCount, GetMessageTime, timeSetEvent, timeGetSystemTime, QueryPerformanceCounter function The first command 0167: 00401ff seti; set interrupt, initialization code ends two, intercept time function part (as an example of timegettime, the code is listed in the order of tracking) TimegetTime JMP 832a 002a; this is the first instructions after TimegetTime modified 0167: 832A 002A CLI; At this time [ESP] = 40BF2C, that is, the next instruction of the TimegetTime function in the game program ... (6) each register is set to the stack and the MOV EBP, ESP 0167: 832A 0033 Call 832a 0038; the current EIP Stack (ie the address of the next instruction) 0167: 832A 0038 POP EDI; Remove the current command address XOR DI, DI MOV ESI, EDI; assign the 64K memory address to ESI; at this time, ESI = EDI = 832a 0000 add ESI, 0040 2102 SUB ESI, 0040 213B; Survere Map Code First Address Push ESI 0167: 832A 004B Call EDI; ESI is a passive parameter; return TimegetTime code Restore 0167: 832A 004D Call 832a 0052; 0167: 832a 0052 Pop EDI XOR Di, Di; so the technique of the technique, Call [EDI 0000FEED]; call the original TimegetTime function SUB EAX, [EDI 0000 FF30]; minus the first call TimegetTime results MUL DWORD PTR [EDI 0000 Fe30]; Multiply the multiple MOV EBX, 00100000 DIV EBX, 00100000 DIV EBX; divided by constant 100000 Add Eax, [EDI 0000FE20] MOV EAX, 004021F3 SUB EAX, 0040213B Add Eax, EDI; or more command returns the value of the TimegetTime function returns the value of the TimeGetTime function PUSH EAX; EAX In order to pass the parameter Call Edi; return the TimegetTime first instruction to JMP ... Restore the value of each register, Eax is the modified return value return; at this time [ESP] = 40bf2c, execute RET will return to In the game; 0167: 832a 0000 Call 832a 0005 0167: 832a 0005 0167: 832a 0005 POP EDI XOR DI, DI; old set ^ _ ^ MOV ESI, [EDI 0000 Fe00]; this address saves LDT linear base MOV EAX, [ESP 04] MOV [ESI 10], AX SHR EAX, 10 MOV [ESI 16], AX; the above code converts the offset of the memory door descriptor in the LDT 2 to the incoming parameter ... MOV EAX, 0000 0F00 Call EAX; Call Subriginal Modification TimegetTime Code 0167: 832A 0027 RET 4; pop-up parameters, return; 0167: 832A f000 call 0014: 00000000 RET 0; 000c: 832a 0097 Call 832A 009C 000c: 832A 009C POP EDI MOV EX, [EDI 0000 FeE0] MOV EBX, [EDI 0000 Fee0] MOV [EBX], EAX MOV EAX, [EDI 0000 Fe44] MOV [EBX 04], EAX RETF Note: EDI 0000 Fe40 starts the first 8 bytes of the original TimegetTime function, the EDI 0000 FeE0 saves the entry address of the TimegetTime function to restore the first 8 bytes of TimegetTime; 000c: 832a 00b8 Call 832a 00bd 000c: 832a 00bd pop EDI XOR DI, DI ... MOV EAX, [EDI 0000 Fe90] MOV EBX, [EDI 0000 Fee0] MOV [EBX], EAX MOV EAX, [EDI 0000fe94] MOV [EBX 04], EAX RETF Note: EDI 0000 Fe90 starts from 8 bytes Save the JMP 832A 002A directive is calculated from the "gear" initialization part of the code, the above code will jMP 832A 002A Write TimegetTime Functions - Be ... Become ...