After learning the structure of PE, try to modify the PE file to realize the function of adding pop-up window to the program
PS: this note does not cover the knowledge points of PE, but focuses on HOOK, disassembly and hard coding. If you don't know much about PE, you can see that the contents related to PE knowledge points are put in the following notes: PE learning note 9: add pop-up window of HOOK program in actual combat (Continued) , you can eat it at ease ( ̄)  ̄) ↗
PE actual combat adds pop-up window to the program
Modification process
To add pop-up windows to the program, the first thing is to understand its modification process
The first thing to modify is the original entry address of the program, and modify it to the address where the pop-up code is located
For the address of the pop-up code, find an area in the PE file that needs to meet the permissions of executable, readable and writable, and then write the pop-up code in this area. Finally, the pop-up code should jump back to the original entry address
The modification process is a very classic HOOK idea, that is, the program executes according to the original process. You modify the code it originally executes, modify it to do what we want to do, and put it back to continue executing the original code after we finish what we want
Figure HOOK modification process
The place that is HOOK is B
Normal process A → B → C
HOOK process A → HOOK B → own code → restore the modified part in B → jump back to the place where B originally wanted to execute → C
Add pop-up window to the program
Pop up code
Since you want to add a pop-up window to the program, you naturally need to know how to display a simple pop-up window through code
Here is a simple pop-up code
#include <Windows.h> int main() { //Call MessageBoxA function //Display a window with no owner window, the content is lyl610abc, the title is tips, and contains only one button: OK MessageBoxA(0, "lyl610abc", "tips", 0); return 0; }
Operation results
MessageBoxA
The following is the document that introduces the use of MessageBoxA. If you are familiar with MessageBoxA, you can skip it and directly skip to the later view disassembly
Function prototype
int MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType );
parameter
uType
The content and behavior of the dialog box. This parameter can be a combination of flags in the following flag groups
To indicate the button displayed in the message box, specify one of the following values:
To display an icon in a message box, specify one of the following values:
To specify a default button, specify one of the following values:
To indicate the mode of the dialog box, specify one of the following values:
To specify additional options, use one or more of the following values:
Return value
Return value type: int
- If the message box has a cancel button, if the ESC key is pressed or the Cancel button is selected, the function will return the IDCANCEL value. If the message box does not have a cancel button, pressing ESC has no effect - unless MB_ The OK button is present. If MB appears_ OK button, press "ESC" key, and the return value is "IDOK".
- If the function fails, the return value is 0. To get extended error information, call GetLastError
- If the function succeeds, the return value is one of the following menu item values:
By setting the uType parameter to the corresponding flag value, the following system icons can be used in the message box
View disassembly
9: MessageBoxA(0,"lyl610abc","tips",0); 00401028 8B F4 mov esi,esp 0040102A 6A 00 push 0 0040102C 68 28 20 42 00 push offset string "tips" (00422028) 00401031 68 1C 20 42 00 push offset string "lyl610abc" (0042201c) 00401036 6A 00 push 0 00401038 FF 15 AC A2 42 00 call dword ptr [__imp__MessageBoxA@16 (0042a2ac)] 0040103E 3B F4 cmp esi,esp 00401040 E8 2B 00 00 00 call __chkesp (00401070)
The key code is intercepted here
0040102A 6A 00 push 0 0040102C 68 28 20 42 00 push offset string "tips" (00422028) 00401031 68 1C 20 42 00 push offset string "lyl610abc" (0042201c) 00401036 6A 00 push 0 00401038 FF 15 AC A2 42 00 call dword ptr [__imp__MessageBoxA@16 (0042a2ac)]
Description of other codes
00401028 8B F4 mov esi,esp //Save the ESP (stack top) before execution to esi 0040103E 3B F4 cmp esi,esp //Compare the esi with the ESP after the call (top of stack) 00401040 E8 2B 00 00 00 call __chkesp (00401070) //Call the function to detect esp
It is used to detect whether the stack remains balanced after calling the function. It is automatically generated by C language. There is no need to pay attention here
Parsing disassembly
0040102A 6A 00 push 0 0040102C 68 28 20 42 00 push offset string "tips" (00422028) 00401031 68 1C 20 42 00 push offset string "lyl610abc" (0042201c) 00401036 6A 00 push 0
The first four lines of code press in four parameters in turn (from right to left), which is related to the call agreement. In Reverse basic note 9 C language inline assembly and call protocol As already said, I won't repeat it here
00401038 FF 15 AC A2 42 00 call dword ptr [__imp__MessageBoxA@16 (0042a2ac)]
Call here, you can see that this is an indirect call in the form of call [address], so here you need to check what is stored in its actual address, that is, its actual call address
Through the memory window, the actual call address is 77D507EA
So the code at this time is equivalent to
00401038 call 77D507EA
Why is this an indirect call? What does 77D507EA stand for?
The reason for using indirect call here is that the import table is referenced. The notes about the contents of the import table and export table will be explained later
The address of the message5077ea function here is box7a
The address of MessageBoxA function of each computer is not necessarily the same, which depends on the user32 of the system DLL (the MessageBoxA called here is provided by user32.dll)
IDA can be used to verify this:
Find user32.0 in the system DLL (in 32-bit xp, there are two in C:\WINDOWS\system32 and in 64 bit system, one in C:\Windows\SysWOW64 (32-bit dll) and one in C:\WINDOWS\system32 (64 bit dll). Which one to use depends on whether the program is 32-bit or 64 bit)
Open it with IDA, find the export table, and then search the export table to get MessageBoxA
You can see that its address is the same as that obtained earlier. It is 77D507EA. The source is verified
Note that the system at this time is XP32-bit. In other higher version systems, the Address here is not necessarily the same as the previous one. This is mainly to explain that the source of the function is related to the import table and export table, and also explain why the addresses of MessageBoxA in different systems are not necessarily the same, so as to pave the way for later learning
The method to accurately obtain the function address is as follows:
If you want to get the address of MessageBoxA function (the same with other functions), first find a program that calls the module to which this function belongs (the module to which MessageBoxA belongs is user32.dll), and use OD attachment to find:
Generally speaking, any graphical program will call user32 DLL, so just take an exe program here. Here, take Dbgview exe as an example
Use OD to open Dbgview Exe, and then click e in the figure, or use the shortcut key Alt+E
In the pop-up window, find user32 DLL, double click
In the pop-up disassembly interface, press the shortcut key Ctrl+N
Then find the address corresponding to MessageBoxA in the new window
The address obtained at this time is the exact MessageBoxA address
Self writing disassembly test
Test code
Now that the function address of MessageBoxA is obtained, there is no need to call it indirectly. You can call it directly, so the self written code is as follows:
#include<stdio.h> #include <windows.h> int MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) { int ret; //The address here is filled in the MessageBoxA address obtained through OD. Each system is not necessarily the same //It was previously tested in xp system. At that time, the MessageBoxA was 77D507EA //At this time, switch to WIN10 X64 test and modify the value of MessageBoxA int addr = 0x76a3ee90; __asm { push hWnd push lpCaption push lpText push uType call addr mov ret, eax } return ret; } int main(int argc, char* argv[]) { MyMessageBoxA(0, "lyl610abc", "tips", 0); return 0; }
test result
It can still pop up normally, and the test is successful
Disassembly to hard coding (bytecode)
Through the previous study, we can know that in the computer, both the executed code and data are stored in binary. In order to facilitate viewing, the hexadecimal viewing tool displays the content in hexadecimal
Therefore, in order to add a pop-up window to the program, it is obvious that instead of directly writing the disassembly into the PE file, it is necessary to write the hard coding (bytecode) corresponding to the disassembly into the PE file
How to convert disassembly into hard coding? This is what the disassembly engine does. The disassembly engine in OD or VC has given the hard code (bytecode) corresponding to disassembly
The content of disassembly engine also belongs to the knowledge related to hard coding. Let's see if we want to open this pit in the future
Slightly modify the disassembly written earlier, write the parameters dead, and remove the reception of the return value
Modify disassembly code
#include<stdio.h> #include <windows.h> void MyMessageBoxA() { //Get the address of MessageBoxA int addr = (int)&MessageBoxA; printf("addr:%X\n", addr); //ASCII code corresponding to "lyl610abc" 6c 79 6c 36 31 30 61 62 63 unsigned char bytes[] = { 0x6c,0x79,0x6c,0x36,0x31,0x30,0x61,0x62,0x63,0x00 }; //ASCII encoding corresponding to "tips" unsigned char bytes2[] = { 0x74,0x69,0x70,0x73 }; //Apply for memory whose attribute is executable, readable and writable LPVOID _lpText = VirtualAlloc(NULL, sizeof(byte), MEM_COMMIT, PAGE_EXECUTE_READWRITE); //Apply for memory whose attribute is executable, readable and writable LPVOID _lpCaption = VirtualAlloc(NULL, sizeof(byte), MEM_COMMIT, PAGE_EXECUTE_READWRITE); //Hard coded into the requested privileged memory WriteProcessMemory(INVALID_HANDLE_VALUE, (LPVOID)_lpText, (BYTE*)bytes, sizeof(bytes), 0); //Hard coded into the requested privileged memory WriteProcessMemory(INVALID_HANDLE_VALUE, (LPVOID)_lpCaption, (BYTE*)bytes2, sizeof(bytes2), 0); __asm { push 0 push _lpCaption push _lpText push 0 call addr } } int main(int argc, char* argv[]) { MyMessageBoxA(); return 0; }
OD analog code operation
First summarize what the above modified disassembly code has done
- Get the function address of MessageBoxA
- Write the ASCII code corresponding to the string to a piece of readable and writable memory
- Press in parameters
- Call MessageBoxA function
- After calling, jump back to the original code to be executed
Then reproduce in OD operation
Use OD to load a random file containing user32 DLL module program, here I directly take the program compiled by the previous code as a demonstration
Follow the steps summarized above
1. The address of messageboxa in OD is known and does not need to be obtained
2. Write the ASCII code corresponding to the string into a piece of readable and writable memory
First, select a piece of readable and writable memory. Obviously, the code to be executed next must be readable, writable and executable. Therefore, there is no need to apply for memory here. Just overwrite the following code
The problem of selecting memory is solved. The next step is to write the ASCII code corresponding to the string into memory, but this should be put after the pressing parameter. The reason will be explained later. Now let's look at the pressing parameter first
3. Press in parameters
The first parameter is 0. Directly modify its corresponding disassembly to push 0
The second parameter is_ lpCaption, the string to be written is "tips", but at this time, the string has not been written into memory, that is, the memory address of the string is not determined, but an approximate range can be determined. The place where the string is to be stored is not far below, so you can fill in any memory address not far from here for occupation, After determining the memory address of the string, come back and modify it
Here, just choose the following address 00401156
Therefore, the disassembly is modified to push 0x00401156
The third parameter is_ lpText, the string to be written is "lyl610abc", and the previous_ Like lpCaption, first fill in the space occupied by push xxxx, and then come back to modify it
Therefore, the disassembly is still modified to push 0x00401156
The fourth parameter is 0. Directly modify its corresponding disassembly to push 0
4. Call MessageBoxA function
Directly modify the disassembly to call MessageBoxA
5. After calling, jump back to the original code to be executed
This is to jump back to the program entry after the pop-up code is executed after the simulation
Here, just simulate a long jump, and modify the disassembly code to jmp 000412D0
6. Fill string into memory
The following code can be used as a data area because the previous absolute jump will not be executed, which is why the filling of the string should be placed later
Fill first_ lpText, which is "lyl610abc"
Select the line under jump, right click → binary → edit
Select ASCII and fill in the string "lyl610abc" to be written to memory
After filling in, select the Hex line and add 00 after it (the string ends with '\ 0')
Get after adding 00
Then confirm
Get after modification
This is the third parameter_ lpText can be corrected by changing the previous disassembly of pressing in the third parameter to push 0x00401148
Fill in the second parameter in the same way_ lpCaption, or "tips"
Here, first record its address as 0x00401152, and then start to modify it
After modification:
Finally, correct the address used to occupy the previous push
After modification, record the modified hexadecimal code as
6A 00 68 52 11 40 00 68 48 11 40 00 6A 00 E8 A7 F6 94 77 E9 88 01 C4 FF 6C 79 6C 36 31 30 61 62 63 00 74 69 70 73 00
After the modification is completed, press F8 continuously and step by step until you call user32 Messageboxa this
You can see that the corresponding parameters are OK
Finally, press F8 to step by step to see the results:
Be able to pop up the box according to the code and complete (•) ̀ ω •́ ) ✧
explain
Due to space limitation, this note mainly explains the compilation process of pop-up code. Later, the notes slightly modify the above hard code, write it into the PE file, and then modify the PE entry point to achieve the ultimate goal
Finally, we have come to the actual combat link. The number of people in the previous notes on the introduction of knowledge points is endless. I hope that through the actual combat, we can arouse everyone's interest and learn together to make common progress O(∩∩) O
The download links of the program modified by OD in this article are in the links below. Welcome to download and communicate
https://www.dslt.tech/article-436-1.html
Copyright notice: This article was originally created by lyl610abc. Welcome to share this article. Please keep the source for reprint