Register for your free account! | Forgot your password?

Go Back   elitepvpers > MMORPGs > Conquer Online 2 > CO2 Programming
You last visited: Today at 18:30

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



[Tutorial] Reversing Spell Encryption

Discussion on [Tutorial] Reversing Spell Encryption within the CO2 Programming forum part of the Conquer Online 2 category.

Reply
 
Old   #1
 
elite*gold: 20
Join Date: Aug 2005
Posts: 1,734
Received Thanks: 1,001
[Tutorial] Reversing Spell Encryption

It has been quite a while since I last wrote a tutorial related to Conquer. This is mostly useless because as far as I know the spell encryption has already been reversed long time ago. The purpose of this post / tutorials is to help people understand how it's possible to find functions and implement them in desired language by reverse engineering. This will also be kind of log for me on how I approach reversing.

This reverse engineering was performed on a unnamed private server so I'm not sure how the encryption will look on the newer Conquer but it should be relatively same unless it has been changed for this private server.

First thing you need to do is to attach OllyDBG 1.0 or 2.1 version to Conquer.exe. I won't be covering how to bypass possible Anti Cheat methods that I understand are present on the newer Conquer client.

I approached this reversing by applying some previous knowledge of packets and their types. I know that the attack packet type is 0x3FE in hexadecimal so the first thing I did was searching for that constant in Conquer.exe. I then placed breakpoints at the locations where we are using the constant 0x3FE and used the SS-skill in conquer in order to trigger this function. This lead me to the following function

Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073F162  /$  55            PUSH EBP                                 ; Conquer.0073F162(guessed Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7,Arg8)
0073F163  |.  8BEC          MOV EBP,ESP
0073F165  |.  56            PUSH ESI
0073F166  |.  57            PUSH EDI
0073F167  |.  8B7D 0C       MOV EDI,DWORD PTR SS:[ARG.2]
0073F16A  |.  8BF1          MOV ESI,ECX
0073F16C  |.  85FF          TEST EDI,EDI
0073F16E  |.  75 07         JNZ SHORT 0073F177
0073F170  |.  33C0          XOR EAX,EAX
0073F172  |.  E9 F3000000   JMP 0073F26A
0073F177  |>  8B86 04040000 MOV EAX,DWORD PTR DS:[ESI+404]
0073F17D  |.  53            PUSH EBX
0073F17E  |.  6A 2C         PUSH 2C
0073F180  |.  59            POP ECX
0073F181  |.  66:8908       MOV WORD PTR DS:[EAX],CX
0073F184  |.  8B86 04040000 MOV EAX,DWORD PTR DS:[ESI+404]
0073F18A  |.  B9 FE030000   MOV ECX,3FE
0073F18F  |.  66:8948 02    MOV WORD PTR DS:[EAX+2],CX
0073F193  |.  E8 44FFEFFF   CALL <JMP.&WINMM.timeGetTime>            ; Jump to WINMM.timeGetTime
0073F198  |.  8B8E 04040000 MOV ECX,DWORD PTR DS:[ESI+404]
0073F19E  |.  8941 04       MOV DWORD PTR DS:[ECX+4],EAX
0073F1A1  |.  E8 36FFEFFF   CALL <JMP.&WINMM.timeGetTime>            ; Jump to WINMM.timeGetTime
0073F1A6  |.  8B8E 04040000 MOV ECX,DWORD PTR DS:[ESI+404]
0073F1AC  |.  8941 08       MOV DWORD PTR DS:[ECX+8],EAX
0073F1AF  |.  8B86 04040000 MOV EAX,DWORD PTR DS:[ESI+404]
0073F1B5  |.  66:8B4D 1C    MOV CX,WORD PTR SS:[ARG.6]
0073F1B9  |.  66:8948 1C    MOV WORD PTR DS:[EAX+1C],CX
0073F1BD  |.  8B86 04040000 MOV EAX,DWORD PTR DS:[ESI+404]
0073F1C3  |.  66:8B50 08    MOV DX,WORD PTR DS:[EAX+8]
0073F1C7  |.  BB FF000000   MOV EBX,0FF
0073F1CC  |.  66:23D3       AND DX,BX
0073F1CF  |.  43            INC EBX
0073F1D0  |.  66:0FAFD3     IMUL DX,BX
0073F1D4  |.  66:0355 20    ADD DX,WORD PTR SS:[ARG.7]
0073F1D8  |.  BB 21370000   MOV EBX,3721
0073F1DD  |.  66:33D3       XOR DX,BX
0073F1E0  |.  66:8950 1E    MOV WORD PTR DS:[EAX+1E],DX
0073F1E4  |.  8B86 04040000 MOV EAX,DWORD PTR DS:[ESI+404]
0073F1EA  |.  8B55 10       MOV EDX,DWORD PTR SS:[ARG.3]
0073F1ED  |.  8978 0C       MOV DWORD PTR DS:[EAX+0C],EDI
0073F1F0  |.  8B86 04040000 MOV EAX,DWORD PTR DS:[ESI+404]
0073F1F6  |.  8950 10       MOV DWORD PTR DS:[EAX+10],EDX
0073F1F9  |.  8B86 04040000 MOV EAX,DWORD PTR DS:[ESI+404]
0073F1FF  |.  66:8B55 14    MOV DX,WORD PTR SS:[ARG.4]
0073F203  |.  66:8950 14    MOV WORD PTR DS:[EAX+14],DX
0073F207  |.  8B86 04040000 MOV EAX,DWORD PTR DS:[ESI+404]
0073F20D  |.  66:8B55 18    MOV DX,WORD PTR SS:[ARG.5]
0073F211  |.  66:8950 16    MOV WORD PTR DS:[EAX+16],DX
0073F215  |.  8B86 04040000 MOV EAX,DWORD PTR DS:[ESI+404]
0073F21B  |.  66:8B55 08    MOV DX,WORD PTR SS:[ARG.1]
0073F21F  |.  66:8950 18    MOV WORD PTR DS:[EAX+18],DX
0073F223  |.  0FB7C1        MOVZX EAX,CX
0073F226  |.  3D E8030000   CMP EAX,3E8
0073F22B  |.  5B            POP EBX
0073F22C  |.  7C 39         JL SHORT 0073F267
0073F22E  |.  3D EA030000   CMP EAX,3EA
0073F233  |.  7E 23         JLE SHORT 0073F258
0073F235  |.  3D 06040000   CMP EAX,406
0073F23A  |.  74 1C         JE SHORT 0073F258
0073F23C  |.  3D 65040000   CMP EAX,465
0073F241  |.  74 15         JE SHORT 0073F258
0073F243  |.  3D 7E040000   CMP EAX,47E
0073F248  |.  74 0E         JE SHORT 0073F258
0073F24A  |.  3D 88040000   CMP EAX,488
0073F24F  |.  74 07         JE SHORT 0073F258
0073F251  |.  3D 8D040000   CMP EAX,48D
0073F256  |.  75 0F         JNE SHORT 0073F267
0073F258  |>  8BB6 04040000 MOV ESI,DWORD PTR DS:[ESI+404]
0073F25E  |.  B8 79620000   MOV EAX,6279
0073F263  |.  66:3146 1E    XOR WORD PTR DS:[ESI+1E],AX
0073F267  |>  33C0          XOR EAX,EAX
0073F269  |.  40            INC EAX
0073F26A  |>  5F            POP EDI
0073F26B  |.  5E            POP ESI
0073F26C  |.  5D            POP EBP
0073F26D  \.  C2 2000       RETN 20
With some knowledge it's easy to determine that this is the function that is used for sending the attack packet. You can how the packet is constructed.

For example this part

Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073F17E  |.  6A 2C         PUSH 2C
0073F180  |.  59            POP ECX
0073F181  |.  66:8908       MOV WORD PTR DS:[EAX],CX
0073F184  |.  8B86 04040000 MOV EAX,DWORD PTR DS:[ESI+404]
0073F18A  |.  B9 FE030000   MOV ECX,3FE
0073F18F  |.  66:8948 02    MOV WORD PTR DS:[EAX+2],CX
0073F193  |.  E8 44FFEFFF   CALL <JMP.&WINMM.timeGetTime>            ; Jump to WINMM.timeGetTime
0073F198  |.  8B8E 04040000 MOV ECX,DWORD PTR DS:[ESI+404]
0073F19E  |.  8941 04       MOV DWORD PTR DS:[ECX+4],EAX
0073F1A1  |.  E8 36FFEFFF   CALL <JMP.&WINMM.timeGetTime>            ; Jump to WINMM.timeGetTime
0073F1A6  |.  8B8E 04040000 MOV ECX,DWORD PTR DS:[ESI+404]
0073F1AC  |.  8941 08       MOV DWORD PTR DS:[ECX+8],EAX
should look relatively familiar if you have done any work on private server. A little explanation on the code. The [EAX] can be thought of as the start of the packet in memory so the first thing we do here is move 0x2C to the start of the packet and the type 0x3FE to Packet+2 and so on. Then couple lines down we assign Packet+4 and Packet+8 value of timeGetTime-function. I'm sure there's tutorial floating around with more in-depth guide on reversing the packet structures so I'll just scratch the surface on that.

Anyways, lets continue on our reversing adventure. For me OllyDBG 2.1 shows that the function first function is called from 4 different addresses which I suspect handle different attack functionality such as melee and magic attack. The next thing I did was breakpointing each of the calls until I found the one that is called when using skill on Conquer. This lead me to the following assembly

Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073B4CD  |.  FF75 10       PUSH DWORD PTR SS:[EBP+10]               ; /Arg8 = A4E08569
0073B4D0  |.  8B4D EC       MOV ECX,DWORD PTR SS:[EBP-14]            ; |
0073B4D3  |.  E8 4C1F0000   CALL 0073D424                            ; |
0073B4D8  |.  0FB740 1C     MOVZX EAX,WORD PTR DS:[EAX+1C]           ; |
0073B4DC  |.  50            PUSH EAX                                 ; |Arg7
0073B4DD  |.  FF75 0C       PUSH DWORD PTR SS:[EBP+0C]               ; |Arg6 => [ARG.EBP+0C]
0073B4E0  |.  8D8D C4FBFFFF LEA ECX,[EBP-43C]                        ; |
0073B4E6  |.  57            PUSH EDI                                 ; |Arg5
0073B4E7  |.  56            PUSH ESI                                 ; |Arg4
0073B4E8  |.  FF75 10       PUSH DWORD PTR SS:[EBP+10]               ; |Arg3 => [ARG.EBP+10]
0073B4EB  |.  53            PUSH EBX                                 ; |Arg2
0073B4EC  |.  6A 18         PUSH 18                                  ; |Arg1 = 18
0073B4EE  |.  E8 6F3C0000   CALL 0073F162                            ; \Conquer.0073F162
OllyDBG tells me that the attack packet function takes total of 8 parameters. You can think of the attack packet function as this C# equivalent:

Code:
byte[] ConstructAttackPacket(uint AttackType, uint AttackerUID, uint TargetUID, ushort X, ushort Y, ushort SpellID, ushort SubType, uint TargetUID)
This I of course determine later. At this point I had no idea what these parameters were because they were encrypted.

The function from the start until ConstructAttackPacket is the following:

Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073B412  /$  68 30040000   PUSH 430                                 ; Conquer.0073B412(guessed Arg1,Arg2,Arg3,Arg4,Arg5)
0073B417  |.  B8 49C88900   MOV EAX,0089C849                         ; Entry point
0073B41C  |.  E8 12680F00   CALL 00831C33
0073B421  |.  894D E8       MOV DWORD PTR SS:[EBP-18],ECX
0073B424  |.  FF75 08       PUSH DWORD PTR SS:[EBP+8]                ; /Arg2 => [ARG.EBP+8]
0073B427  |.  8D45 EC       LEA EAX,[EBP-14]                         ; |
0073B42A  |.  50            PUSH EAX                                 ; |Arg1 => ARG.EBP-14
0073B42B  |.  E8 F3F2FFFF   CALL 0073A723                            ; \Conquer.0073A723
0073B430  |.  8365 FC 00    AND DWORD PTR SS:[EBP-4],00000000
0073B434  |.  837D EC 00    CMP DWORD PTR SS:[EBP-14],0
0073B438  |.  75 17         JNE SHORT 0073B451
0073B43A  |>  834D FC FF    OR DWORD PTR SS:[EBP-4],FFFFFFFF
0073B43E  |.  8B4D F0       MOV ECX,DWORD PTR SS:[EBP-10]
0073B441  |.  85C9          TEST ECX,ECX
0073B443  |.  74 05         JZ SHORT 0073B44A
0073B445  |.  E8 CA09CDFF   CALL 0040BE14                            ; [Conquer.0040BE14
0073B44A  |>  32C0          XOR AL,AL
0073B44C  |.  E9 C6010000   JMP 0073B617
0073B451  |>  0FB745 08     MOVZX EAX,WORD PTR SS:[EBP+8]
0073B455  |.  2D BE140000   SUB EAX,14BE
0073B45A  |.  6A 03         PUSH 3                                   ; /Arg2 = 3
0073B45C  |.  50            PUSH EAX                                 ; |Arg1
0073B45D  |.  E8 9299F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
0073B462  |.  8B5D 0C       MOV EBX,DWORD PTR SS:[EBP+0C]
0073B465  |.  33C3          XOR EAX,EBX
0073B467  |.  35 5D910000   XOR EAX,0000915D
0073B46C  |.  0FB7C0        MOVZX EAX,AX
0073B46F  |.  8945 0C       MOV DWORD PTR SS:[EBP+0C],EAX
0073B472  |.  8B45 10       MOV EAX,DWORD PTR SS:[EBP+10]
0073B475  |.  05 E64A6F74   ADD EAX,746F4AE6
0073B47A  |.  33C3          XOR EAX,EBX
0073B47C  |.  35 63242D5F   XOR EAX,5F2D2463
0073B481  |.  C1C0 0D       ROL EAX,0D
0073B484  |.  8945 10       MOV DWORD PTR SS:[EBP+10],EAX
0073B487  |.  8B45 14       MOV EAX,DWORD PTR SS:[EBP+14]
0073B48A  |.  05 EE22FFFF   ADD EAX,FFFF22EE
0073B48F  |.  6A 01         PUSH 1                                   ; /Arg2 = 1
0073B491  |.  50            PUSH EAX                                 ; |Arg1
0073B492  |.  E8 5D99F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
0073B497  |.  8BF0          MOV ESI,EAX
0073B499  |.  8B45 18       MOV EAX,DWORD PTR SS:[EBP+18]
0073B49C  |.  05 2289FFFF   ADD EAX,FFFF8922
0073B4A1  |.  6A 05         PUSH 5                                   ; /Arg2 = 5
0073B4A3  |.  33F3          XOR ESI,EBX                              ; |
0073B4A5  |.  50            PUSH EAX                                 ; |Arg1
0073B4A6  |.  81F6 D62E0000 XOR ESI,00002ED6                         ; |
0073B4AC  |.  E8 4399F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
0073B4B1  |.  8BF8          MOV EDI,EAX
0073B4B3  |.  33FB          XOR EDI,EBX
0073B4B5  |.  83C4 18       ADD ESP,18
0073B4B8  |.  8D8D C4FBFFFF LEA ECX,[EBP-43C]
0073B4BE  |.  81F7 9BB90000 XOR EDI,0000B99B
0073B4C4  |.  E8 393C0000   CALL 0073F102                            ; [Conquer.0073F102
0073B4C9  |.  C645 FC 01    MOV BYTE PTR SS:[EBP-4],1
And the interesting parts are

Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073B455  |.  2D BE140000   SUB EAX,14BE
0073B45A  |.  6A 03         PUSH 3                                   ; /Arg2 = 3
0073B45C  |.  50            PUSH EAX                                 ; |Arg1
0073B45D  |.  E8 9299F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
0073B462  |.  8B5D 0C       MOV EBX,DWORD PTR SS:[EBP+0C]
0073B465  |.  33C3          XOR EAX,EBX
0073B467  |.  35 5D910000   XOR EAX,0000915D
0073B46C  |.  0FB7C0        MOVZX EAX,AX
0073B46F  |.  8945 0C       MOV DWORD PTR SS:[EBP+0C],EAX
0073B472  |.  8B45 10       MOV EAX,DWORD PTR SS:[EBP+10]
0073B475  |.  05 E64A6F74   ADD EAX,746F4AE6
0073B47A  |.  33C3          XOR EAX,EBX
0073B47C  |.  35 63242D5F   XOR EAX,5F2D2463
0073B481  |.  C1C0 0D       ROL EAX,0D
0073B484  |.  8945 10       MOV DWORD PTR SS:[EBP+10],EAX
0073B487  |.  8B45 14       MOV EAX,DWORD PTR SS:[EBP+14]
0073B48A  |.  05 EE22FFFF   ADD EAX,FFFF22EE
0073B48F  |.  6A 01         PUSH 1                                   ; /Arg2 = 1
0073B491  |.  50            PUSH EAX                                 ; |Arg1
0073B492  |.  E8 5D99F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
0073B497  |.  8BF0          MOV ESI,EAX
0073B499  |.  8B45 18       MOV EAX,DWORD PTR SS:[EBP+18]
0073B49C  |.  05 2289FFFF   ADD EAX,FFFF8922
0073B4A1  |.  6A 05         PUSH 5                                   ; /Arg2 = 5
0073B4A3  |.  33F3          XOR ESI,EBX                              ; |
0073B4A5  |.  50            PUSH EAX                                 ; |Arg1
0073B4A6  |.  81F6 D62E0000 XOR ESI,00002ED6                         ; |
0073B4AC  |.  E8 4399F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
0073B4B1  |.  8BF8          MOV EDI,EAX
0073B4B3  |.  33FB          XOR EDI,EBX
0073B4B5  |.  83C4 18       ADD ESP,18
0073B4B8  |.  8D8D C4FBFFFF LEA ECX,[EBP-43C]
0073B4BE  |.  81F7 9BB90000 XOR EDI,0000B99B
0073B4C4  |.  E8 393C0000   CALL 0073F102                            ; [Conquer.0073F102
0073B4C9  |.  C645 FC 01    MOV BYTE PTR SS:[EBP-4],1
The above code is responsible for encrypting the SpellID, X, Y and TargetUID values.

I started by inserting a breakpoint at the start of the function. I then looked the registers / function calls to find some familiar values. It helped me quite bit that I knew SS skill ID is 1046 so I knew to look for it and I found it at

Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073B455  |.  2D BE140000   SUB EAX,14BE
0073B45A  |.  6A 03         PUSH 3                                   ; /Arg2 = 3
0073B45C  |.  50            PUSH EAX                                 ; |Arg1
0073B45D  |.  E8 9299F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
0073B462  |.  8B5D 0C       MOV EBX,DWORD PTR SS:[EBP+0C]
0073B465  |.  33C3          XOR EAX,EBX
0073B467  |.  35 5D910000   XOR EAX,0000915D
0073B46C  |.  0FB7C0        MOVZX EAX,AX
0073B46F  |.  8945 0C       MOV DWORD PTR SS:[EBP+0C],EAX
Where EAX holds the value 1046 (SS) at the beginning. As you can see we substract the constant 0x14BE from this and afterwards call a function which takes this and constant 3 as parameters. This function is repeated at couple of locations

Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073B45A  |.  6A 03         PUSH 3                                   ; /Arg2 = 3
0073B45C  |.  50            PUSH EAX                                 ; |Arg1
0073B45D  |.  E8 9299F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073B48F  |.  6A 01         PUSH 1                                   ; /Arg2 = 1
0073B491  |.  50            PUSH EAX                                 ; |Arg1
0073B492  |.  E8 5D99F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073B4A1  |.  6A 05         PUSH 5                                   ; /Arg2 = 5
0073B4A3  |.  33F3          XOR ESI,EBX                              ; |
0073B4A5  |.  50            PUSH EAX                                 ; |Arg1
0073B4A6  |.  81F6 D62E0000 XOR ESI,00002ED6                         ; |
0073B4AC  |.  E8 4399F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
And here is the 00664df4 function contents

Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
00664DF4  /$  56            PUSH ESI                                 ; Conquer.00664DF4(guessed Arg1,Arg2)
00664DF5  |.  57            PUSH EDI
00664DF6  |.  8B7C24 10     MOV EDI,DWORD PTR SS:[ARG.2]
00664DFA  |.  85FF          TEST EDI,EDI
00664DFC  |.  7C 05         JL SHORT 00664E03
00664DFE  |.  83FF 10       CMP EDI,10
00664E01  |.  7C 21         JL SHORT 00664E24
00664E03  |>  68 13020000   PUSH 213
00664E08  |.  68 14A29000   PUSH OFFSET 0090A214                     ; ASCII "e:\cq2client\cq2client-65.3\basecode\basefunc.h"
00664E0D  |.  68 F8A19000   PUSH OFFSET 0090A1F8                     ; ASCII "nBits >= 0 && nBits < 16"
00664E12  |.  68 E8C38A00   PUSH OFFSET 008AC3E8                     ; ASCII "ASSERT"
00664E17  |.  68 60C38A00   PUSH OFFSET 008AC360                     ; /Format = ""
00664E1C  |.  E8 E8A2FDFF   CALL 0063F109                            ; \Conquer.0063F109
00664E21  |.  83C4 14       ADD ESP,14
00664E24  |>  8B5424 0C     MOV EDX,DWORD PTR SS:[ARG.1]
00664E28  |.  BE FFFF0000   MOV ESI,0FFFF
00664E2D  |.  6A 10         PUSH 10
00664E2F  |.  23D6          AND EDX,ESI
00664E31  |.  59            POP ECX
00664E32  |.  2BCF          SUB ECX,EDI
00664E34  |.  8BC2          MOV EAX,EDX
00664E36  |.  D3E0          SHL EAX,CL
00664E38  |.  8BCF          MOV ECX,EDI
00664E3A  |.  D3EA          SHR EDX,CL
00664E3C  |.  5F            POP EDI
00664E3D  |.  0BC2          OR EAX,EDX
00664E3F  |.  23C6          AND EAX,ESI
00664E41  |.  5E            POP ESI
00664E42  \.  C3            RETN
What this function does is that first it checks the second parameter and compares it to 0x10. If it is lower it calculates some value otherwise it will give you an error ("nBits >= 0 && nBits < 16") and from this we can determine that the second parameter should always be 0-15.

Afterwards at
Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
00664E24  |> \8B5424 0C     MOV EDX,DWORD PTR SS:[ARG.1]
00664E28  |.  BE FFFF0000   MOV ESI,0FFFF
00664E2D  |.  6A 10         PUSH 10
00664E2F  |.  23D6          AND EDX,ESI
00664E31  |.  59            POP ECX
00664E32  |.  2BCF          SUB ECX,EDI
00664E34  |.  8BC2          MOV EAX,EDX
00664E36  |.  D3E0          SHL EAX,CL
00664E38  |.  8BCF          MOV ECX,EDI
00664E3A  |.  D3EA          SHR EDX,CL
00664E3C  |.  5F            POP EDI
00664E3D  |.  0BC2          OR EAX,EDX
00664E3F  |.  23C6          AND EAX,ESI
We move the second parameter to EDI-register (MOV EDI,DWORD PTR SS:[ARG.2]).

We move the first parameter to EDX-register and constant 0xFFFF to ESI register. Then couple lines lower we assign ECX value 0x10 (PUSH 10 && POP ECX) and subtract the second parameter from it and assign it to ECX. One of the above functions used constant 0x03 as the second parameter so at this point ecx would be 0x10 - 0x03 = 0x0D.

We then move the first parameter (EDX) to EAX and shift it left by the value of ECX. We then move ECX value of the second parameter (EDI) and shift the first parameter right by the amount assigned to second parameter. After this we OR these two calculations together and AND it by the constant 0xFFFF (ESI)

The above might be a bit confusing but in the end you can translate this function to C# equivalent of:

Code:
 static uint Shift(uint Value, int Amount)
        {
            int LeftShift = 16 - Amount;
            Value = Value & 0xFFFF;
            Value = (Value << LeftShift) | (Value >> Amount);
            return Value & 0xFFFF;
        }
Which hopefully is a bit clearer.

Now we can return back to this part of the code

Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073B455  |.  2D BE140000   SUB EAX,14BE
0073B45A  |.  6A 03         PUSH 3                                   ; /Arg2 = 3
0073B45C  |.  50            PUSH EAX                                 ; |Arg1
0073B45D  |.  E8 9299F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
0073B462  |.  8B5D 0C       MOV EBX,DWORD PTR SS:[EBP+0C]
0073B465  |.  33C3          XOR EAX,EBX
0073B467  |.  35 5D910000   XOR EAX,0000915D
0073B46C  |.  0FB7C0        MOVZX EAX,AX
Which is a bit clearer now. We first substract 0x14BE from the SpellID then call Shift(SpellID, 3). Afterwards we have some XOR values and I was able to determine with different accounts that the line

Code:
MOV EBX,DWORD PTR SS:[EBP+0C]
moves the player UID to EBX-register so the value of the Shift function is XORed by UID and then by 0x915D. Then we basically get the lowest 16 bits and move it to EAX again (the MOVZX part, you can look up what it really does if you are interested)

At this point we can begin to construct our C# code to Encrypt the information.

Code:
static void Encrypt(ushort SpellID, ushort X, ushort Y, uint UID, uint TargetUID)
        {
            uint ID = (uint)(SpellID - 0x14BE);
            ID = Shift(ID, 3) ^ UID;
            ID = ID ^ 0x915D;
            ID = ID & 0xFFFF;
        }
Next up is the Target UID encryption (or so I believe, just a guess really at this point)

Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073B472  |.  8B45 10       MOV EAX,DWORD PTR SS:[EBP+10]
0073B475  |.  05 E64A6F74   ADD EAX,746F4AE6
0073B47A  |.  33C3          XOR EAX,EBX
0073B47C  |.  35 63242D5F   XOR EAX,5F2D2463
0073B481  |.  C1C0 0D       ROL EAX,0D
What we do here is we move value of some point in memory to EAX. Add 0x746F4AE6 to it. XOR it by players UID, XOR this by 0x5f2d2463 and finally ROL it by 0x0D.

This translates to the following in C#:

Code:
 uint eax = TargetUID + 0x746F4AE6;
            eax = eax ^ UID;
            eax = eax ^ 0x5F2D2463;
            eax = rol(eax, 0x0D);

static uint rol(uint value, int amount)
        {
            return (value << amount) | (value >> (32 - amount));
        }

Next up we have the X/Y encryption

Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0073B487  |.  8B45 14       MOV EAX,DWORD PTR SS:[EBP+14]
0073B48A  |.  05 EE22FFFF   ADD EAX,FFFF22EE
0073B48F  |.  6A 01         PUSH 1                                   ; /Arg2 = 1
0073B491  |.  50            PUSH EAX                                 ; |Arg1
0073B492  |.  E8 5D99F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
0073B497  |.  8BF0          MOV ESI,EAX
0073B499  |.  8B45 18       MOV EAX,DWORD PTR SS:[EBP+18]
0073B49C  |.  05 2289FFFF   ADD EAX,FFFF8922
0073B4A1  |.  6A 05         PUSH 5                                   ; /Arg2 = 5
0073B4A3  |.  33F3          XOR ESI,EBX                              ; |
0073B4A5  |.  50            PUSH EAX                                 ; |Arg1
0073B4A6  |.  81F6 D62E0000 XOR ESI,00002ED6                         ; |
0073B4AC  |.  E8 4399F2FF   CALL 00664DF4                            ; \Conquer.00664DF4
0073B4B1  |.  8BF8          MOV EDI,EAX
0073B4B3  |.  33FB          XOR EDI,EBX
0073B4B5  |.  83C4 18       ADD ESP,18
0073B4B8  |.  8D8D C4FBFFFF LEA ECX,[EBP-43C]
0073B4BE  |.  81F7 9BB90000 XOR EDI,0000B99B
This starts by retrieving the X coordinate from memory and adding 0xFFFF22EE to it. We then call the Shift function with this new X and 1 as parameters. The result of this is then XORed by players UID and then XOR by 0x2ED6. This may look a bit weird but the result of the shift is moved to ESI register which then is modified couple lines down (XOR ESI, EBX and XOR ESI, 00002ED6).

Next we have the Y coordinate encryption which is retrieved from memory to EAX register (MOV EAX,DWORD PTR SS:[EBP+18]). We then add 0xFFFF8922 to it and call Shift(Y, 0x05). This result is XORed by player UID and then by 0x0000B99B.

All in all the Encryption function looks like this.

Code:
static void Encrypt(ushort SpellID, ushort X, ushort Y, uint UID, uint TargetUID)
        {
            uint ID = (uint)(SpellID - 0x14BE);
            ID = Shift(ID, 3) ^ UID;
            ID = ID ^ 0x915D;
            ID = ID & 0xFFFF;


            Console.WriteLine("ID: " + ID.ToString("X8"));
            
            uint eax = TargetUID + 0x746F4AE6;
            eax = eax ^ UID;
            eax = eax ^ 0x5F2D2463;
            eax = rol(eax, 0x0D);

            Console.WriteLine("Target UID: " + eax.ToString("X8"));

            uint encX = X + 0xFFFF22EE;
            encX = Shift(encX, 1);
            encX = encX ^ UID ^ 0x2ED6;
            Console.WriteLine("X: " + encX.ToString("X8"));

            uint encY = Y + 0xFFFF8922;
            encY = Shift(encY, 5);
            encY = encY ^ UID ^ 0xB99B;

            Console.WriteLine("Y: " + encY.ToString("X8"));
        }
You may also be interested in Decrypting the values and in that case you can use the following code

Code:
static uint ror(uint value, int amount)
        {
            return (value >> amount) | (value << (32 - amount));
        }
        static uint RightShift(uint Value, int Amount)
        {
            int RightShift = 16 - Amount;
            Value = Value & 0xFFFF;
            Value = (Value >> RightShift) | (Value << Amount);
            return Value & 0xFFFF;
        }
        static void Decrypt(ushort SpellID, uint X, uint Y, uint UID, uint TargetUID)
        {
            uint ID = (uint)(SpellID ^ 0x915D);
            ID = ID ^ UID;
            ID = RightShift(ID, 3);
            ID += 0x14BE;
            ID = ID & 0xFFFF;

            uint Target = ror(TargetUID, 0x0D);
            Target = Target ^ 0x5F2D2463;
            Target = Target ^ UID;
            Target -= 0x746F4AE6;

            uint decX = X ^ 0x2ED6 ^ UID;
            decX = RightShift(decX, 1);
            decX -= 0xFFFF22EE;
            decX = decX & 0xFFFF;

            uint decY = Y ^ 0xB99B ^ UID;
            decY = RightShift(decY, 5);
            decY -= 0xFFFF8922;
            decY = decY & 0xFFFF;
        }
There might be somethings that could be optimized better but that's up to you.
tanelipe is offline  
Thanks
17 Users
Old 06/15/2014, 18:13   #2
 
anone.ious's Avatar
 
elite*gold: 0
Join Date: May 2014
Posts: 48
Received Thanks: 3
Wow thanks good job
anone.ious is offline  
Reply


Similar Threads Similar Threads
[Tutorial-Collection] Metin2 Reversing/Hacking
07/03/2015 - Metin2 Guides & Templates - 149 Replies
Hey Epvp'ler. Ich habe mich dazu entschieden die ungebildete Metin2-Community mal ein bisschen auf Vordermann zu bringen und release hier meine private Playlist mit Reversing-Tutorials für Metin2. Die Tutorials sind so vom Niveau her für Anfänger, jedoch nicht für welche, die keine Ahnung von Memory, Assembler und Cheat Engine und sowas haben. Also WriteProcessMemory() solltet ihr schonmal gehört haben. Wenn ihr Ideen für weitere Videos oder Fragen habt, fragt einfach hier, wenn sie mir...
[ C++ / Reversing | Tutorial ] Detour + Code Cave mit WPM
01/03/2010 - Coding Tutorials - 4 Replies
Moin leute, habe hier ein kleines Tutorial geschrieben wie man Funktionen auf seinen eigenen Code umleitet mit WriteProcessMemory. Ihr solltet jedoch schon wissen wie man WriteProcessMemory verwendet. Als Beispiel habe ich das Spiel Counterstrike genommen und Whitewalls gemacht. Das Tutorial ist NICHT dazu da um zu zeigen wie man Hacks schreibt und wie diese Funktionieren. Programme die benutzt werden: OllyDBG Credits für den White Walls code: b2k5



All times are GMT +1. The time now is 18:30.


Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2026 elitepvpers All Rights Reserved.