0041CAED > 8BCE MOV ECX,ESI
0041CAEF . E8 8E6DFEFF CALL 00403882
0041CAF4 . 85C0 TEST EAX,EAX
0041CAF6 . 75 0C JNZ SHORT 0041CB04
0041CAF8 . 57 PUSH EDI
0041CAF9 . 57 PUSH EDI
0041CAFA . 68 58E26500 PUSH 0065E258 ; ASCII "LoadUserKnightsRank Load Fail"
0041CAFF . E9 6E020000 JMP 0041CD72
0041CB04 > 8BCE MOV ECX,ESI
0041CB06 . E8 BF70FEFF CALL 00403BCA
0041CB0B . 85C0 TEST EAX,EAX
0041CB0D . 75 0C JNZ SHORT 0041CB1B
0041CB0F . 57 PUSH EDI
0041CB10 . 57 PUSH EDI
0041CB11 . 68 30E26500 PUSH 0065E230 ; ASCII "LoadUserPersonalRank Load Fail"
00421B01 |> 6A 00 PUSH 0 ; /Arg3 = 00000000
00421B03 |. 68 70170000 PUSH 1770 ; |Arg2 = 00001770
00421B08 |. 6A 64 PUSH 64 ; |Arg1 = 00000064
00421B0A |. 8BCE MOV ECX,ESI ; |
00421B0C |. E8 9CB61A00 CALL 005CD1AD ; \005CD1AD
00421B11 |. 33FF XOR EDI,EDI
00421B13 |. B8 C8000000 MOV EAX,0C8
00421B18 |. 57 PUSH EDI ; /Arg3 => 00000000
00421B19 |. 50 PUSH EAX ; |Arg2 => 000000C8
00421B1A |. 50 PUSH EAX ; |Arg1 => 000000C8
00421B1B |. 8BCE MOV ECX,ESI ; |
00421B1D |. E8 8BB61A00 CALL 005CD1AD ; \005CD1AD
00421B22 |. 57 PUSH EDI ; /Arg3
00421B23 |. 68 D0840000 PUSH 84D0 ; |Arg2 = 000084D0
00421B28 |. 68 90010000 PUSH 190 ; |Arg1 = 00000190
00421B2D |. 8BCE MOV ECX,ESI ; |
00421B2F |. E8 79B61A00 CALL 005CD1AD ; \005CD1AD
00421B34 |. 57 PUSH EDI ; /Arg3
00421B35 |. 68 E0930400 PUSH 493E0 ; |Arg2 = 000493E0
00421B3A |. 68 E8030000 PUSH 3E8 ; |Arg1 = 000003E8
00421B3F |. 8BCE MOV ECX,ESI ; |
00421B41 |. E8 67B61A00 CALL 005CD1AD ; \005CD1AD
00421B46 |. 57 PUSH EDI ; /Arg3
00421B47 |. 68 407E0500 PUSH 57E40 ; |Arg2 = 00057E40
00421B4C |. 68 2C010000 PUSH 12C ; |Arg1 = 0000012C
00421B51 |. 8BCE MOV ECX,ESI ; |
00421B53 |. E8 55B61A00 CALL 005CD1AD ; \005CD1AD
00421B58 |. 57 PUSH EDI ; /Arg3
00421B59 |. 68 60EA0000 PUSH 0EA60 ; |Arg2 = 0000EA60
00421B5E |. 68 F4010000 PUSH 1F4 ; |Arg1 = 000001F4
00421B63 |. 8BCE MOV ECX,ESI ; |
00421B65 |. E8 43B61A00 CALL 005CD1AD ; \005CD1AD
00421B6A |. 57 PUSH EDI ; /Arg3
00421B6B |. 68 C0270900 PUSH 927C0 ; |Arg2 = 000927C0
00421B70 |. 68 58020000 PUSH 258 ; |Arg1 = 00000258
00421B75 |. 8BCE MOV ECX,ESI ; |
00421B77 |. E8 31B61A00 CALL 005CD1AD ; \005CD1AD
00421B7C |> 5F POP EDI
00421B7D |. 5E POP ESI
00421B7E |. 5B POP EBX
00421B7F |. C9 LEAVE
00421B80 \. C3 RETN
This is in milliseconds, so I need to go:
12 hours * 60 minutes * 60 seconds * 1000 milliseconds = 43,200,000 milliseconds
00421B75 |. 8BCE MOV ECX,ESI ; |
00421B77 |. E8 31B61A00 CALL 005CD1AD ; \005CD1AD
00421B7C |> 5F POP EDI
00421B7D |. 5E POP ESI
00421B7E |. 5B POP EBX
00421B7F |. C9 LEAVE
00421B80 \. C3 RETN; end of CEbenezerDlg::GetTimeFromINI()
00421B81 CC INT3; Woo, a code-cave!
00421B82 CC INT3
00421B83 CC INT3
00421B84 CC INT3
00421B85 CC INT3
00421B86 CC INT3
00421B87 CC INT3
00421B88 CC INT3
00421B89 CC INT3
00421B8A CC INT3
00421B8B CC INT3
00421B8C CC INT3
0041DF0C . E9 FC000000 JMP 0041E00D
In our code-cave:-
We actually patched over this instruction, so not only are we putting it in for the sake of making sure everything's as it was, but we actually NEED to store the address of the CEbenezerDlg instance in ESI so that we have a 'backup copy' of the address. We need this because the two CALLs we make will be messy and change ECX on us, so we'll need to keep reverting it. Ugh!
CODE
0041E00D > 8BF1 MOV ESI,ECX
Check to see if EAX is 44C (1100 - our timer!):
CODE
0041E00F . 3D 4C040000 CMP EAX,44C
If it's not our timer (if it doesn't match 1100, the value will be non-zero - so it will take the jump), jump to "backToMainFunction".
CODE
0041E014 75 15 JNZ SHORT 0041E02B
The original function will use EAX to work out which timer it is, but it will be replaced with the result of CEbenezerDlg::LoadUserKnightsRank() and CEbenezerDlg::LoadUserPersonalRank() if we don't push it onto the stack (and take it off again).. so push it onto the stack.
CODE
0041E016 . 50 PUSH EAX
Call CEbenezerDlg::LoadUserKnightsRank()
Note: You'll notice I'm not passing the pointer here, that is because just before we jumped to the code-cave, the value was moved to ESI from ECX - so, ECX will definitely be what we want at this point in time.
CODE
0041E017 . E8 6658FEFF CALL 00403882
Just in case that function changed it (trust me, it will), we'll set ECX to ESI (the preserved pointer to the instance of the CEbenezerDlg class).
CODE
0041E01C . 8BCE MOV ECX,ESI
..and then call CEbenezerDlg::LoadUserPersonalRank():
CODE
0041E01E . E8 A75BFEFF CALL 00403BCA
You get the deal by now.
CODE
0041E023 . 8BCE MOV ECX,ESI
A call to CEbenezerDlg::LoadAllKnights2() (in order to shorten the guide, I plonked this one in now. This one [basically for our purposes] deals with updating the clan grades).
CODE
0041E025 . E8 C94BFEFF CALL 00402BF3
Now that we're done with EAX, we'll pop it off the stack, restoring it back to its original value before the functions changed it.
CODE
0041E02A . 58 POP EAX
backToMainFunction:
Our original code (basically part of an odd process to set ECX to 100 [64 in hex] which is then used to work out what timer it is):
CODE
0041E02B > 6A 64 PUSH 64
0041E02D 59 POP ECX
Finally.. go back to the main function and continue executing the code.
CODE
0041E02E ^E9 DEFEFFFF JMP 0041DF11
Address Disassembly
0041D77B PUSH 258
00421B70 PUSH 258
00432D4E MOV WORD PTR DS:[ESI+EDI*2+4C842],258
00432DB2 MOV WORD PTR DS:[ESI+EDI*2+4C83A],258
0049DFBB CMP ECX,258
005CEEDA PUSH 258
00606B45 PUSH 258
What we're looking for is an argument pushed onto the stack, so it'll start with "PUSH".
This reduces our findings down to 4 possibilities:
Address Disassembly
0041D77B PUSH 258
00421B70 PUSH 258
005CEEDA PUSH 258
00606B45 PUSH 258
Considering 00421B70 is used for SetTimer() in CEbenezer::GetTimeFromINI(), we can eliminate that too, leaving only 3 possibilities:
Address Disassembly
0041D77B PUSH 258
005CEEDA PUSH 258
00606B45 PUSH 258
So, now it's just checking them all out.
Starting with the first at 0041D77B, let's take a look:
CODE
0041D72C > 8B81 94CD0400 MOV EAX,DWORD PTR DS:[ECX+4CD94]
0041D732 . C3 RETN
0041D733 > 53 PUSH EBX
0041D734 . 56 PUSH ESI
0041D735 . 57 PUSH EDI
0041D736 . 8BF1 MOV ESI,ECX
0041D738 . 6A 64 PUSH 64 ; /Arg1 = 00000064
0041D73A . E8 C5FA1A00 CALL 005CD204 ; \005CD204
0041D73F . 68 C8000000 PUSH 0C8 ; /Arg1 = 000000C8
0041D744 . 8BCE MOV ECX,ESI ; |
0041D746 . E8 B9FA1A00 CALL 005CD204 ; \005CD204
0041D74B . 68 90010000 PUSH 190 ; /Arg1 = 00000190
0041D750 . 8BCE MOV ECX,ESI ; |
0041D752 . E8 ADFA1A00 CALL 005CD204 ; \005CD204
0041D757 . 68 E8030000 PUSH 3E8 ; /Arg1 = 000003E8
0041D75C . 8BCE MOV ECX,ESI ; |
0041D75E . E8 A1FA1A00 CALL 005CD204 ; \005CD204
0041D763 . 68 2C010000 PUSH 12C ; /Arg1 = 0000012C
0041D768 . 8BCE MOV ECX,ESI ; |
0041D76A . E8 95FA1A00 CALL 005CD204 ; \005CD204
0041D76F . 68 F4010000 PUSH 1F4 ; /Arg1 = 000001F4
0041D774 . 8BCE MOV ECX,ESI ; |
0041D776 . E8 89FA1A00 CALL 005CD204 ; \005CD204
0041D77B . 68 58020000 PUSH 258 ; /Arg1 = 00000258
0041D780 . 8BCE MOV ECX,ESI ; |
0041D782 . E8 7DFA1A00 CALL 005CD204 ; \005CD204
0041D787 . 8B86 DC000000 MOV EAX,DWORD PTR DS:[ESI+DC]
0041D78D . 33DB XOR EBX,EBX
0041D78F . 3BC3 CMP EAX,EBX
0041D791 . 74 08 JE SHORT 0041D79B
0041D793 . 53 PUSH EBX ; /ExitCode => 0
0041D794 . 50 PUSH EAX ; |hThread
0041D795 . FF15 38996800 CALL DWORD PTR DS:[<&KERNEL32.TerminateT>; \TerminateThread
0041D79B > 399E E8000000 CMP DWORD PTR DS:[ESI+E8],EBX
0041D7A1 . 74 18 JE SHORT 0041D7BB
0041D7A3 . FFB6 E4000000 PUSH DWORD PTR DS:[ESI+E4] ; /BaseAddress
0041D7A9 . FF15 34996800 CALL DWORD PTR DS:[<&KERNEL32.UnmapViewO>; \UnmapViewOfFile
0041D7AF . FFB6 E0000000 PUSH DWORD PTR DS:[ESI+E0] ; /hObject
0041D7B5 . FF15 30996800 CALL DWORD PTR DS:[<&KERNEL32.CloseHandl>; \CloseHandle
Push 44c (1100) onto the stack - this is our timer's unique identifier, and will be passed to KillTimer()
CODE
0041D71B 68 4C040000 PUSH 44C
Call KillTimer() to destroy our timer
CODE
0041D720 E8 DFFA1A00 CALL 005CD204
Reset ECX back to ESI (pointer to the instance of CEbenezerDlg)
CODE
0041D725 8BCE MOV ECX,ESI
Back to the original code, we'll push 64 (100) onto the stack for the next call to KillTimer()
CODE
0041D727 6A 64 PUSH 64
And jump back to the original code!
CODE
0041D729 EB 0F JMP SHORT 0041D73A
00421B75 EB 0B JMP SHORT 00421B82
00421B82 |> 8BCE MOV ECX,ESI
00421B84 |. E8 24B61A00 CALL 005CD1AD
00421B89 8BCE MOV ECX,ESI
00421B8B 57 PUSH EDI
00421B8C 68 002E9302 PUSH 2932E00
00421B91 68 4C040000 PUSH 44C
00421B96 ^EB DF JMP SHORT 00421B77
0041DF0C . E9 FC000000 JMP 0041E00D
0041E00D > 8BF1 MOV ESI,ECX
0041E00F . 3D 4C040000 CMP EAX,44C
0041E014 . 75 15 JNZ SHORT 0041E02B
0041E016 . 50 PUSH EAX
0041E017 . E8 6658FEFF CALL 00403882
0041E01C . 8BCE MOV ECX,ESI
0041E01E . E8 A75BFEFF CALL 00403BCA
0041E023 . 8BCE MOV ECX,ESI
0041E025 . E8 C94BFEFF CALL 00402BF3
0041E02A . 58 POP EAX
0041E02B > 6A 64 PUSH 64
0041E02D 59 POP ECX
0041E02E ^E9 DEFEFFFF JMP 0041DF11
0041D71B 68 4C040000 PUSH 44C
0041D720 E8 DFFA1A00 CALL 005CD204
0041D725 8BCE MOV ECX,ESI
0041D727 6A 64 PUSH 64
0041D729 EB 0F JMP SHORT 0041D73A
0041D738 ^EB E1 JMP SHORT 0041D71B