Agreement plug-in production
BY RIX
In the first section, we said that the preparation of the basic tools, the fourth quarter uses the upgrade and the exemption home page to do basic exercises. The fourth quarter is not much different from the ordinary game modifier, just a modified data, a modified code. In this section, we will make plug-in production by modifying the code in the DLL. In fact, in the DLL dynamic modification code and the method of the previous section, it is more than something to rewrite.
The principle is the same as the function in the previous section, is called WriteProcessMemory.
The task of this section is to intercept the received data, and the data transmitted can be processed. Generally analyze the received data before analyzing online games. For the procedure of the big story, how to go analysis in the middle is not said, it depends on his ability to adjust. However, for the largest call client program before 9.16, there is a lot of debugging information (or may be scripting information), and the approval program can find that the program is always after printing the debug information, then doing actual work. Among them, I am very interested in the field of "rx_decode" and see where the call is called:
.TEXT: 00449D
4f
154 push offset arx_decode; "rx_decode"
The place in the near future is the network function RECV, so it can be understood that after receiving the data, print the debug information, then jump to:
.TEXT: 00449D95 154 PUSH EBP
The place continues to perform, through constant tracking discovery, most of the program is executed to the address:
.Text: 00449DED 154 MOV [EAX], EDI
Moreover, the content in [EDI] is almost similar at the same time. By random opening interrupt in the game, the content DUMP in [EDI] can be found, and then it can be found that the content inside is relatively It is constant. If you are lucky, you can intercept the chat data, you will find the content of the chat. This is a bit like a luck. However, if you use the following methods, you can don't have to touch your luck. First, we found that EDI is an address of a data, and EBP is the length of the data we receive. When you feel doubt about the content, we want to execute the statement [EDI] in [EDI], the length of DUMP is the value in the EBP. So we make memory patches through W32DASM. After using the W32DASM anti-compilation program, use shortcuts Ctrl L to load the program into memory, do not let the program execute, shortcut Ctrl F12 jump code window address to 00449DED, It is convenient to restore the code. Press CTRL F12 in the debug window to jump to 00449ded.
We will perform memory patch here. Click the Patch Code button to write the memory code directly. The patch at 00449DED is as follows:
: 00449DED E90ECA0400 JMP 00496800
The content of 00496800 address is an idle memory. In the IDA, you can see that there is no use of this memory anywhere in the program, we will make a modification of the program here. When the program executes to 00449ded, it will jump to 00496800 and then execute, so we must also modify the code at 00496800, use Ctrl F12 to jump to 00496800, start to patch:
: 00496800 50 Push EAX; save the value of each register
00496801 53 PUSH EBX
00496802 51 PUSH ECX
: 00496803 52 Push EDX
: 00496804 55 Push EBP; EBP is the length of the data received
00496805 57 Push EDI; EDI is the data address
: 00496806 6804040000 Push 00000404; Send intercept message ID to the plus program
: 0049680B A1D0664900 MOV EAX, DWORD PTR [004966D0] [004966D0] is included in the window handle of the plug-in window
00496810 50 PUSH EAX
: 00496811 3EFF1574924700 CALL DWORD PTR DS: [00479274] DS: [00479274] For SendMessage's function addresses, call the sendMessage function to send commands
00496818
5A
POP EDX; Restore the registers
00496819 59 POP ECX
:
0049681A
5b POP EBX
0049681B 58 POP EAX
:
0049681C
8938 MOV DWORD PTR [EAX], EDI; call the original operation, because we skip some operations when we play patch, so it will operate here.
0049681
5F
POP EDI
:
0049681F
5E POP ESI
00496820 5D POP EBP
: 00496821 E9CC35FBFF JMP 00449DF2; After jumping back to the original address, then execute
The above is the full code of the intercepting patch. When using, you must first fill the upper plug-in window handle in [004966D0], or no way.
When using W32DASM, the benefits are that we see is the virtual address used in execution, and W32DASM gives the assembly code while giving the code 16 credit representation. After the patch is finished, the rest is how to put the patch in the target program.
After the plug-in window is created, we send WM_USER 2 to the plug-in window to command the plug-in window to perform the operation of modifying the biggest program.
The following is a specific modification:
Void TWGHOKFORM :: Modifyxy2 (TMESSAGE MESSAGE)
{
DWORD DWIDOLD1, DWIDOLD2, DWIDOLD3, DWIDOLD4, DWIDOLD5;
DWORD ID = getCurrentProcessId ();
Handle Handle1 = OpenProcess (Process_All_Access, False, ID);
IF (wghandle)
{
Byte getRecv1 [] =
{
0xE9, 0x0e, 0xca, 0x04, 0x00
}; //5
BYTE GETRECV2 [] =
{
0x50, 0x53, 0x51, 0x52, 0x55, 0x57, 0x68, 0x04, 0x04, 0x00,
0x00, 0xA1, 0xD0, 0x66, 0x49, 0x00, 0x50, 0x3e, 0xff, 0x15,
0x74, 0x92, 0x47, 0x00, 0x
5A
, 0x59, 0x5b, 0x58, 0x89, 0x38,
0x
5F
, 0x5e, 0x5d, 0xe9, 0xcc, 0x35, 0xfb, 0xFF
}; // 38
VirtualProtectex (Handle1, (Void *) (0x004966D0), 4, Page_Readwrite,
& dwidold1);
IF ((WriteProcessMemory (Handle1, (void *) (0x004966D0), & WGHANDLE, 4,
NULL)) == false)
{
ShowMessage ("Write Handle Error!");
Return;
}
VirtualProtectex (Handle1, (Void *) (0x004966D0), 4, DWIDOLD1, & DWIDOLD1);
VirtualProtectex (Handle1, (Void *) (0x00449ded), 5, Page_Readwrite,
& dwidold4);
IF ((WriteProcessMemory (Handle1, (Void *) (0x00449ded), GetRecv1, 5, Null
) == false)
{
SHOWMESSAGE ("Intercepting Repair Refractive Patch Error!");
}
VirtualProtectex (Handle1, (Void *) (0x00449DED), 5, DWIDOLD4, & DWIDOLD4;
VirtualProtectex (Handle1, (void *) (0x00496800), 38, Page_Readwrite,
& dwidold5);
IF ((WriteProcessMemory (Handle1, (void *) (0x00496800), GetRecv2, 38,
NULL)) == false)
{
ShowMessage ("Intercepting Receive Patch Error!");
}
VirtualProtectex (Handle1, (Void *) (0x00496800), 38, DWIDOLD5, & DWIDOLD5);
}
}
Use custom messages in CB, you need to join in the header file:
#define WM_USER_MODIF (WM_USER 2) / / Change the message of the big discretion
#define WM_USER_GETSEND (WM_USER 1) // Interception to the message received by sending data
#define WM_USER_APIHOOK (WM_USER 5) // APIHOOK intercends the received message
#define WM_USER_GETRECV (WM_USER 4) // The modified program sends the message to the plug-in window.
In the plug-in window (I am TWGHOKFORM), add a function void modifyxy2 (TMESSAGE Message);
Void getRecv (TMESSAGE Message);
Add a message mapping declaration in protected: Keywords:
Begin_MESSAGE_MAP
VCL_MESSAGE_HANDLER (WM_USER_MODIF, TMESSAGE, MODIFYXY2) VCL_MESSAGE_HANDLER (WM_USER_APIHOK, TMESSAGE, HOOKAPITEST)
VCL_MESSAGE_HANDLER (WM_USER_GETSEND, TMESSAGE, GETSEND)
VCL_MESSAGE_HANDLER (WM_USER_GETRECV, TMESSAGE, GETRECV)
END_MESSAGE_MAP (TFORM)
The above is all the interception of receiving data. Combined with the previous code, run the program, you can find that the intercepted data is all the decrypted game data, as for the data analysis, look at yourself, here give a parsed code frame:
#define cmdvoid (a) /
Void cmdsay ## a (int cmd, int layth, char * date)
#define recvcase (CMD, Length, DATA) /
Case cmd: /
CMDSAY ## cmd (cmd, length, data); /
Break
Disclaimer in Class:
Cmdvoid (10);
CMDVOID (11);
Cmdvoid (21);
In the received function, GetRecv:
Void TWGHOKFORM :: GetRecv (TMessage Message)
{
IF (message.wparam == 1)
{
CmdRecvState = Recvcmd; // If the received is 1 character, the received command is
}
Else IF (message.wparam == 2)
{
CmdRecvState = recvlength; // If the received length is 2 characters, the length of the data to be received is
}
Else
{
cmdrecvState = Recvdata; / / Otherwise, the received is data
}
Static int CMD, Datalength;
Switch (cmdrecvState)
{
Case Recvcmd:
CMD = * ((int *) (%age.lparam);
Return;
Case recvlength:
Datales = * ((INT *) (INT *);
Return;
Case Recvdata:
IF (Datalength == Message.wParam)
{
CMDSAY (CMD, DATALENGTH, (CHAR *) message.lparam; // If the packet is not split, the command is explained
}
Else
{/ / Otherwise, print this package is now
Memo1-> lines-> add ("Note: This data is incomplete:");
Ansistring astemp1 = "[Accept] [";
ask1.cat_sprintf ("% x] [", cmd);
Astemp1.cat_sprintf ("receiving length:% D actual length:% D] [", datalength, message.wparam);
BYTE * TEMP = (Byte *) Message.lparam;
For (int i = 0; i { astemp1.cat_sprintf ("% 0.2x", TEMP [i]); } astemp1.cat_sprintf ("] ["); For (int i = 0; i IF (Temp [i]> = 0x20) astemp1.cat_sprintf ("% C", TEMP [I]); Else astemp1.cat_sprintf ("."); } astemp1.cat_sprintf ("]"); Memo1-> lines-> add (astemp1); } Return; } The procedure is only very simple to intercept and resolve the packet, and these packages should be merged in real applications for the split package. The above reception rules are valid for the larger, the big-calling program is valid. The set of data of the big call will be transmitted into 3 times. First, the name word is received, this is 1 byte length, then the length of the data to receive, this is 2 bytes, the next is data. If the data that is real, the data should be different, indicating that this package is split. For the program after 9.16, the big saying is not necessarily in this rule, so the above only adapts to the program before 9.16. Here is the function of cmdsay: Void TWGHOKFORM :: Cmdsay (int CMD, INT Length), char * DATE { Switch (cmd) { Recvcase (10, Length, Date); Recvcase (11, Length, Date); Recvcase (21, Length, Date); DEFAULT: / / Unqualified command Ansistring astemp1 = "[Accept] ["; ask1.cat_sprintf ("% x] [", cmd); astemp1.cat_sprintf ("% d] [", length); BYTE * TEMP = (Byte *) Date; For (INT i = 0; I { astemp1.cat_sprintf ("% 0.2x", TEMP [i]); } astemp1.cat_sprintf ("] ["); For (INT i = 0; I IF (Temp [i]> = 0x20) astemp1.cat_sprintf ("% C", TEMP [I]); Else astemp1.cat_sprintf ("."); astemp1.cat_sprintf ("]"); Memo1-> lines-> add (astemp1); Break; } } All is all, to intercept, and similar to the sending command, you can analyze it yourself. In the first few tutorials, I have said that the patch's attention is said, and I will not say it here. For the program after 9.16, I only did a few studies, mainly because there is no big amount of time and mood to do these things, here only give a preliminary tip: 1. For the transmitted data, some parts may adopt a secondary encryption. 2. For the received data, the program converts the data into the transformation and data transfer of the address after the data is changed to the floating point number. 3, the program will receive and send in a thread (this possibility, because 9.16 is more than 9.16 more than 9.16). 4, the data is stored in the floating point number, and the encryption process may be converted into floating point numbers, but the encryption will be converted into floating point numbers until the last time will be converted into an integer transmission. Since the largest floating point and integer conversion is performed inside the Bigns, the current big-speaking program is very costly CPU resource. In the following code: INT I; FLOAT K = (float) i; // uses floating point registers, this time is very short I = (int) k; // When compiling, it will be converted with its own floating point integer, not the mathematical coprocessor for conversion. This conversion is approximately 12-60 times slower than using floating point registers. or more. Use IDA4.7 to see the library function _ftol after the reverse compilation. Slow reason is because the library function is done for mathematical calculations, not for efficiency in the game. This is the main reason for the big summons after 9.16. For the program after 9.16, the same processing can also be performed, but the lookup of the code address is more troublesome when debugging. If you don't like yourself to write the code array, you can write a code patch tool according to the PE file. I will not talk about this. In fact, I haven't written myself, and it is not enough time. People are lazy. In the previous APIHOOK section (tutorial three), my API class is a bit wrong, here is correct: In Apihook.h Private: Pfnorig, Proc Pfnhook, Bool FexCludeapiHookMod; Void WinAPI ReplaceiaTryNoneMod (PCSTR PszcalleemodName, Proc Pfnorig, Proc Pfnhook, HModule Hmodcaller, Handle Handle); Void WinApi FixUpnewlyLoadedModule (HModule HMOD, DWORD DWFLAGS); Should be changed to: Private: // Pfnorig, Proc Pfnhook, Bool FexCludeapihookMod; this is not to remove clean comments Void WinAPI ReplaceiaTryNoneMod (PCSTR PszcalleemodName, Proc Pfnorig, Proc Pfnhook, HModule Hmodcaller, Handle Handle); Void WinApi FixUpnewlyLoadedModule (HModule HMOD, DWORD DWFLAGS); APIHOK.CPP: M_Module = getModuleHandle (pszcalleemodname); ReplaceiatenTryinonemod (m_pszcalleemodName, M_PFNORIG, M_PFNHOK, M_MODULE, prochandle; Should be modified to: m_module = hmod; ReplaceiatenTryinonemod (m_pszcalleemodName, M_PFNORIG, M_PFNHOK, M_MODULE, prochandle; Last Alan gave me the source code I got up after I uploaded his code and found that he only did a tutorial. I put the source code and gave him a copy, and I should see it soon. Contact information about Alan: E-mail: tyr_alan@hotmal.com If you have questions about his code, you can send him an email. The main content is finally finished, than I want to have less, the next section mainly explains the good treatment so that the plug-in looks more professional. Since the next section is not the main content, it may be dragged.