QQ Lianliankan stand-alone version: qqlk.exe
Title:
1. Find the exe of the program itself
2. Remove the advertisement in the program
3. Write a QQ plug-in
Tools used:
OD
PEID
ImpREC
VS2013
Test environment:
Virtual machine win7 platform 32-bit
1. Initial interface
We found that opening a real program went through two layers of advertising.
When we click directly on the real program
Qqllk.exe (big advertisement) - > qqllk.ocx (small advertisement) - > kyodai.exe (real code, but its code has been extracted). The routine is layer by layer
1.1: use PE tool to query basic information
Remember: when we get a program, we first use PE tools for comprehensive analysis and try to collect more information
The program is an MFC program written by VC6
Open OD and find that the code of wmain function is wrong
2: OD tracker
Idea:
Through testing the software, we found that the program is to open two advertisements and then run the real program.
Then go to the CreateProcessA or W breakpoint
2.1: big advertisement (QQ watch starter)
Summary:
Find big ads and call small ads
2.2: small advertisement (Baidu connection)
Idea:
Directly down CreateProcessA or W breakpoint
Suspicious place:
The thread suspension here is very suspicious. We opened the main program directly and found that the PE file was modified. However, opening the main program indirectly through advertising can run normally. We can suspect that the PE file code was restored (small advertising Baidu connection).
2.3 attach the main program with OD when the program is suspended (preferably before restoring the thread)
We found that the software is written in a typical VC6.0:
Find wmain function
At this time, the code of wmain has not been repaired
2.4 when we run through advertisement 2 (Baidu connection), we attach it again
Summary:
We can speculate that the program can run normally only through the repair of these two advertisements. Because we found that the thread stopped in the second advertisement,
When the ad 2 (Baidu connection) program is run, the code is added and the repair is completed. Then we can judge that the program is repaired between the suspended thread and the recovery thread through ad 2 (Baidu connection).
Through the above features:
We can boldly infer the API used by the program:
Generally, remote modification of the other party's memory data is used
//1. Open process
OpenProcess open process
//2. Write to the opposite process space
Parameter Description:
BOOL WINAPI WriteProcessMemory(
_ In_ HANDLE hProcess, // process handle
_ In_ LPVOID lpBaseAddress, // Pointer to the data to be written
_ In_ LPCVOID lpBuffer, // buffer address
_ In_ SIZE_T nSize, // Bytes to write
_ Out_ SIZE_T *lpNumberOfBytesWritten // Returns the actual read and write bytes
);
SuspendThread suspends the thread
ResumeThread Recovery thread
be careful:
Handling method of OD attachment failure
2.5: open two, one of which OD attaches kyodai.exe to the next breakpoint in winmain, so as to know when it has been modified
2.6: open two OD, one of which is attached to ad 2 (Baidu link), and the WriteProcessMemory breakpoint
And remember the modified address: 43817A
Go to another additional kyodai.exe main program to view the modified place (just inside the wmain function call)
Follow up wmaincall and find that the code has been fixed
2.7: you can Dump the main program after the program executes WriteProcessMemory
2.7.1: or Dump the thread before resuming the thread
Because the dump at the OEP is relatively clean without pollution, remember that the OEP address 438048 - base address 400000 = 38048
2.8: repair IAT table with ImportREC
Go to the file that you just used the OD plug-in dump to overwrite it
2. Remove the advertisement in the program
3. Write a QQ plug-in:
Reverse search is for data, as long as you find the code that operates the map data
3.1: first judge what program is written
VC6 release dynamics
3.2: use PE tools to analyze and find key API s
rand key API
3.3: start at rand
We found that there are many places where rand is called, and we can only filter and find the most similar places again and again
No key code found in the first place, pending
The second. kml is dedicated to storing landmark files, and it is suspicious with memcpy
Important data:
483AC8 Map template
12BB50 Map template (483AC8 memory copy to it)
[Esi+0x195C]=12BB50 Map template
Map width 19
Map height 11
Follow up call
call function:
① : request heap space
② : randomly generate data from heap space
③ : give the randomly generated data in the heap space to the 12BB50 map template (fill in all non-zero data)
④ : free heap space
3.4 in order to judge whether the map game data operates one map or multiple maps, directly start the game and observe the 12BB50 data
We observe that the map data is just D1 (209 = width 19 * height 11)
Idea:
We found that a prop is that the compass automatically helps us find two places that can be eliminated. We can start by modifying the compass without going to the inverse algorithm.
realization:
Drop a hardware breakpoint at the map data
Stack return
The value stored in the stack is not fixed, so you need to find some fixed values
ESI = [45DCF8]
Get address
MOV ECX,DWORD PTR DS:[ESI+0x1E84]
Get address=
ECX = [ESI+0X1E84] map buffer = [ECX+4] map start = map buffer + 8
ECX = [[45DCF8]+ 0x1E84]
summary dd [[[45DCF8]+0x1e84]+4]+8
3.3 inject DLL to realize the call of analog compass
/* 0041DE53 | . 8D8E 94040000 lea ecx, dword ptr ds : [esi + 0x494] 0041DE59 | . 52 push edx 0041DE5A | . 53 push ebx 0041DE5B | . 53 push ebx 0041DE5C | .FF50 28 call dword ptr ds : [eax + 0x28] */ _asm { mov eax,0x45DCF8 mov eax, dword ptr[eax] lea ecx, dword ptr[eax+0x494] push 0xf0 push 0 push 0 mov eax,0x0041E691 call eax }
3.4 finding array subscripts for compass positioning
[Ebp-0x28]129d8c
[Ebp-0x20]129d94
Then we directly write the breakpoint to the hardware under the two parameters passed in from the outside
Found it broken
Let's simulate the call inside
Compare our program
We use dll injection to simulate
The following codes are specifically implemented:
//Analog call code //We found that there is no base address for esi+0x19F0 //But esi+0x19f0 is the same as [ESI+0X1E84] //Then we use esi+0x1E84(esi has base address) instead of esi+0x19f0 /* 0041E75E > \8B8E F0190000 mov ecx, dword ptr ds : [esi + 0x19F0]; ecx = this Pointer first address virtual function mark + 4 map array first address; Case F0(BM_GETCHECK) of switch 0041E749 0041E764 . 8D45 D8 lea eax, dword ptr ss : [ebp - 0x28]; POINT structure 0041E767 . 50 push eax 0041E768 . 8D45 E0 lea eax, dword ptr ss : [ebp - 0x20]; POINT 0041E76B . 50 push eax 0041E76C.E8 CEAA0000 call dumo_.0042923F; Returns the coordinates of two flags that can be eliminated */ POINT FirstDot = { 0 }; //XY coordinate point of the first Xiaole POINT SecondDot = { 0 }; //XY coordinate point of the second Xiaole MessageBox(0, L"Found the injection point", 0, 0); _asm{ mov eax, 0x45DCF8 mov eax, dword ptr[eax] //Take the value 12A1F4 in 45DCF8 mov ecx, dword ptr[eax + 0x1E84] //Take the value 013A83D0 in 12C078. The first four bytes in it are virtual function table + 4 is the first address of the map //The above three sentences are equivalent to mov ecx,[esi+0x19F0] lea eax, dword ptr[FirstDot] push eax lea eax, dword ptr[SecondDot] push eax mov eax, 0x42923F call eax //The function returns two subscripts that can eliminate chess pieces }
3.5 now that you have all the array subscripts, you can find the call API to eliminate
Just simulate these six parameters
//Analog code //6 parameters //00129bb8 00000000 //00129bbc 0012bb50 map header address //00129bc0 00129bec chess piece address A //00129bc4 00129bf4 chess piece address B //00129bc8 019b8400 the address is 13683D0+30 //formula //mov eax, 0x45DCF8 //mov eax, dword ptr[eax] //mov ecx, dword ptr[eax + 0x1E84] //00129bcc 00000004 fixed value push 4 //Fixed value mov ebx,ReEcx add ebx,0x30 push ebx //13683D0+30 lea eax,[FirstDot] //Coordinate A lea ebx, [SecondDot] //Coordinate B push ebx push eax /******************Get the first address of 12BB50 map***************************/ mov eax, 0x45DCF8 mov ecx, dword ptr[eax] lea eax, dword ptr[ecx + 0x1e84] mov eax, dword ptr[eax] mov eax, dword ptr[eax + 4] push eax /*******************Get the first address of 12BB50 map**************************/ push 0 //Dead value 0 mov eax,0x41C68E call eax //call immediate is not supported