Here's a mini guide for "zoomhack" I've written.
The first thing you need to do is find in the client where the "zooming" takes places. For most games this is pretty easy since the mouse wheel is used to change the zoom factor. Because of this, you need to track down the windows message that is sent when you scroll the mouse. That message is

. Figuring that out requires some basic Win32 programming knowledge.
Once you know the message, you just have to locate it in the client. For some games this is hard, for Silkroad it's easy. You just search for all constants and use the constant for the WM_MOUSEWHEEL message, which is 0x20A. In our case on the 205 client, you'll get a few results:
Code:
References in sro_clie: to constant 20A
Address Disassembly Comment
0050F651 MOV DWORD PTR SS:[ESP+20A],EAX
00A7B91F CMP ESI,20A
00A87E08 SUB EAX,20A
Now, you can just BP on them all and start tracing to see which is toggled when you scroll the wheel. You will want to actually BP after the code in the actual handler though. For example on the "CMP ESI,20A" entry, if you follow that in the client, you'll see:
Code:
00A7B91F |> \81FE 0A020000 CMP ESI,20A
00A7B925 |. 74 1F JE SHORT sro_clie.00A7B946
The address of the conditional jump is where you want to BP because that logic is saying if(ESI == 0x20A) goto 0xA7B946.
Likewise for the "SUB EAX,20A" line, you will see a conditional jump and on the new line you'll see:
Code:
00A87E26 |> \0FBFC6 MOVSX EAX,SI ; Case 20A of switch 00A87C57
so that line is what you want to BP since it's the code executed if EAX == 0x20A (switch statement this time).
So that's the basics of how you go about finding areas to trace through based on the mouse wheel event. Once you know that, then it's just a matter of tracing the code.
The first BP that's hit (the switch statement) doesn't have much code in it, so you can be sure that's not the right area. You'll find one pretty empty call and then another call with code related to multithreading (you know with the critical section calls)
The second BP that's hit is a bit more interesting. You will see a function pointer call that you can only trace in real time. Here's the code listing:
Code:
00A7B946 |> \8B4B 18 MOV ECX,DWORD PTR DS:[EBX+18]
00A7B949 |. 0FB743 0A MOVZX EAX,WORD PTR DS:[EBX+A]
00A7B94D |. 8B17 MOV EDX,DWORD PTR DS:[EDI]
00A7B94F |. 8B92 90000000 MOV EDX,DWORD PTR DS:[EDX+90]
00A7B955 |. 51 PUSH ECX
00A7B956 |. 8B4B 14 MOV ECX,DWORD PTR DS:[EBX+14]
00A7B959 |. 51 PUSH ECX
00A7B95A |. 50 PUSH EAX
00A7B95B |. 6A 00 PUSH 0
00A7B95D |. 8BCF MOV ECX,EDI
00A7B95F |. FFD2 CALL NEAR EDX ; sro_clie.006C88F0
00A7B961 |. 5E POP ESI
00A7B962 |. 5D POP EBP
00A7B963 |. 85C0 TEST EAX,EAX
00A7B965 |. 5B POP EBX
00A7B966 |. 0F95C0 SETNE AL
00A7B969 |. 5F POP EDI
00A7B96A |. 83C4 10 ADD ESP,10
00A7B96D |. C2 0400 RETN 4
When you trace into the CALL EDX address, you will see a lot of floating point code. Floating point code always stands out because of the instructions that are used. You can be pretty sure you are in the right area once you start setting floating point code when looking for zoom code.
Here's that complete listing:
Code:
006C88F0 . 56 PUSH ESI
006C88F1 . 8BF1 MOV ESI,ECX
006C88F3 . 80BE A2070000>CMP BYTE PTR DS:[ESI+7A2],1
006C88FA . 0F84 C6000000 JE sro_clie.006C89C6
006C8900 . 83BE DC070000>CMP DWORD PTR DS:[ESI+7DC],0
006C8907 . 74 1F JE SHORT sro_clie.006C8928
006C8909 . 8B4424 14 MOV EAX,DWORD PTR SS:[ESP+14]
006C890D . 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+10]
006C8911 . 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C]
006C8915 . 50 PUSH EAX
006C8916 . 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]
006C891A . 51 PUSH ECX
006C891B . 52 PUSH EDX
006C891C . 50 PUSH EAX
006C891D . 8BCE MOV ECX,ESI
006C891F . E8 8CE8FFFF CALL sro_clie.006C71B0
006C8924 . 5E POP ESI
006C8925 . C2 1000 RETN 10
006C8928 > 0FBF4C24 0C MOVSX ECX,WORD PTR SS:[ESP+C]
006C892D . D986 EC030000 FLD DWORD PTR DS:[ESI+3EC]
006C8933 . 894C24 0C MOV DWORD PTR SS:[ESP+C],ECX
006C8937 . DB4424 0C FILD DWORD PTR SS:[ESP+C]
006C893B . DC35 5869CC00 FDIV QWORD PTR DS:[CC6958]
006C8941 . DEE9 FSUBP ST(1),ST
006C8943 . D95C24 0C FSTP DWORD PTR SS:[ESP+C]
006C8947 . D94424 0C FLD DWORD PTR SS:[ESP+C]
006C894B . D996 EC030000 FST DWORD PTR DS:[ESI+3EC]
006C8951 . D905 8016C400 FLD DWORD PTR DS:[C41680]
006C8957 . D8D1 FCOM ST(1)
006C8959 . DFE0 FSTSW AX
006C895B . DDD9 FSTP ST(1)
006C895D . F6C4 01 TEST AH,1
006C8960 . 75 08 JNZ SHORT sro_clie.006C896A
006C8962 . D99E EC030000 FSTP DWORD PTR DS:[ESI+3EC]
006C8968 . EB 02 JMP SHORT sro_clie.006C896C
006C896A > DDD8 FSTP ST
006C896C > 80BE CF030000>CMP BYTE PTR DS:[ESI+3CF],0
006C8973 . 74 1D JE SHORT sro_clie.006C8992
006C8975 . D905 60BBC600 FLD DWORD PTR DS:[C6BB60]
006C897B . D896 EC030000 FCOM DWORD PTR DS:[ESI+3EC]
006C8981 . DFE0 FSTSW AX
006C8983 . F6C4 41 TEST AH,41
006C8986 . 7A 08 JPE SHORT sro_clie.006C8990
006C8988 . D99E EC030000 FSTP DWORD PTR DS:[ESI+3EC]
006C898E . EB 02 JMP SHORT sro_clie.006C8992
006C8990 > DDD8 FSTP ST
006C8992 > D986 EC030000 FLD DWORD PTR DS:[ESI+3EC]
006C8998 . 6A 00 PUSH 0
006C899A . D95C24 10 FSTP DWORD PTR SS:[ESP+10]
006C899E . 6A 01 PUSH 1
006C89A0 . D94424 14 FLD DWORD PTR SS:[ESP+14]
006C89A4 . 8BCE MOV ECX,ESI
006C89A6 . D996 E8030000 FST DWORD PTR DS:[ESI+3E8]
006C89AC . 8B15 4881F900 MOV EDX,DWORD PTR DS:[F98148] ; sro_clie.00D77228
006C89B2 . D99A 7C030000 FSTP DWORD PTR DS:[EDX+37C]
006C89B8 . E8 23D2FFFF CALL sro_clie.006C5BE0
006C89BD . 6A 00 PUSH 0 ; /Arg1 = 00000000
006C89BF . 8BCE MOV ECX,ESI ; |
006C89C1 . E8 4A310100 CALL sro_clie.006DBB10 ; \sro_clie.006DBB10
006C89C6 > B8 01000000 MOV EAX,1
006C89CB . 5E POP ESI
006C89CC . C2 1000 RETN 10
Now, you kind of need to know ASM to know what to look for, but the zoom limitations really stick out here. They are:
Zoom minimal:
Code:
006C895D . F6C4 01 TEST AH,1
006C8960 . 75 08 JNZ SHORT sro_clie.006C896A
006C8962 . D99E EC030000 FSTP DWORD PTR DS:[ESI+3EC]
006C8968 . EB 02 JMP SHORT sro_clie.006C896C
006C896A > DDD8 FSTP ST
Zoom maximal:
Code:
006C8983 . F6C4 41 TEST AH,41
006C8986 . 7A 08 JPE SHORT sro_clie.006C8990
006C8988 . D99E EC030000 FSTP DWORD PTR DS:[ESI+3EC]
006C898E . EB 02 JMP SHORT sro_clie.006C8992
006C8990 > DDD8 FSTP ST
If you trace the conditional jumps after the test call, you can easily see this code sets the zoom range. For the maximal zoom, you will notice that when you are not at the max, the line:
Code:
006C8986 . /7A 08 JPE SHORT sro_clie.006C8990
will always execute and skip over the code. When you reach the zoom limit, it will not execute and you will execute the next line this time:
Code:
006C8988 . D99E EC030000 FSTP DWORD PTR DS:[ESI+3EC]
which basically changes the current zoom (which is past the max limit) to the max limit.
If you change the JPE to a JMP, then you will never set the zoom to the maximal value, thus creating a "zoom hack".
So, the final code for the zoom hack is simply:
Code:
006C8983 . F6C4 41 TEST AH,41
006C8986 EB 08 JMP SHORT sro_clie.006C8990 ; Always JMP for zoom hack!
006C8988 . D99E EC030000 FSTP DWORD PTR DS:[ESI+3EC]
006C898E . EB 02 JMP SHORT sro_clie.006C8992
006C8990 > DDD8 FSTP ST
You can either repeat this process of tracking down the zoom logic or you can create a binary snippet to search for each time. For a binary snippet, you don't want to select any lines that have physical addresses since those change client to client. You want code that's non-address based instructions or ones that use offsets. That's up to you though. once you know how to find it, it's not too hard to do again.