source: Daodan/src/Daodan_Patch.c@ 1008

Last change on this file since 1008 was 1008, checked in by alloc, 10 years ago

Daodan 3.9: Added AI awareness patch (fixes #36)

File size: 7.2 KB
Line 
1#include "Daodan_Patch.h"
2#include "Patches/Utility.h"
3#include <beaengine/BeaEngine.h>
4
5#include <windows.h>
6#include <stdlib.h>
7#include <string.h>
8
9bool DDrPatch_MakeJump(void* from, void* to)
10{
11 DWORD oldp;
12
13 if (VirtualProtect(from, 5, PAGE_EXECUTE_READWRITE, &oldp))
14 {
15 *((unsigned char*)from) = 0xe9; // jmp rel32
16 from = (char*)from + 1;
17 *(int*)from = (unsigned int)to - (unsigned int)from - 4;
18 VirtualProtect(from, 5, oldp, &oldp);
19 return true;
20 }
21 else
22 return false;
23}
24
25bool DDrPatch_MakeCall(void* from, void* to)
26{
27 DWORD oldp;
28
29 if (VirtualProtect(from, 5, PAGE_EXECUTE_READWRITE, &oldp))
30 {
31 *((unsigned char*)from) = 0xe8; // call rel32
32 from = (char*)from + 1;
33 *(int*)from = (unsigned int)to - (unsigned int)from - 4;
34 VirtualProtect(from, 5, oldp, &oldp);
35 return true;
36 }
37 else
38 return false;
39}
40
41void* DDrPatch_MakeDetour(void* from, void* to)
42{
43 int len = 0;
44
45/*
46 STARTUPMESSAGE("Orig before", 0);
47 DDrPatch_PrintDisasm(from, 10, 0);
48*/
49 DISASM disasm;
50 memset(&disasm, 0, sizeof(DISASM));
51 disasm.EIP = (UIntPtr) from;
52
53 char* trampoline = malloc(40);
54 DDrPatch_NOOP(trampoline, 40);
55 int pos = 0;
56 int branches = 0;
57
58 while (((void*)disasm.EIP - from) < 5) {
59 len = Disasm(&disasm);
60 if (len != UNKNOWN_OPCODE) {
61 if ((disasm.Instruction.Category & 0xffff) == CONTROL_TRANSFER) {
62 if (disasm.Prefix.Number > 0) {
63 STARTUPMESSAGE("Detour: Branch in trampoline area from address 0x%08x with prefixes", from);
64 return (void*)-1;
65 }
66 branches++;
67 int target = disasm.Instruction.AddrValue;
68 bool targetInTrampoline = ((void*)disasm.Instruction.AddrValue - from) < 5;
69 switch (disasm.Instruction.BranchType) {
70 case JmpType:
71 case CallType:
72 if (targetInTrampoline) {
73 int offset = disasm.Instruction.AddrValue - disasm.EIP;
74 if (disasm.Instruction.BranchType == JmpType)
75 DDrPatch_MakeJump(&trampoline[pos], &trampoline[pos]+offset);
76 else
77 DDrPatch_MakeCall(&trampoline[pos], &trampoline[pos]+offset);
78 } else {
79 if (disasm.Instruction.BranchType == JmpType)
80 DDrPatch_MakeJump(&trampoline[pos], (void*)target);
81 else
82 DDrPatch_MakeCall(&trampoline[pos], (void*)target);
83 }
84 pos += 5;
85 break;
86 case RetType:
87 case JECXZ:
88 memcpy(&trampoline[pos], (void*)disasm.EIP, len);
89 pos += len;
90 break;
91 // Opcode +1
92 case JO:
93 case JC:
94 case JE:
95 case JNA:
96 case JS:
97 case JP:
98 case JL:
99 case JNG:
100 if (targetInTrampoline) {
101 memcpy(&trampoline[pos], (void*)disasm.EIP, len);
102 pos += len;
103 } else {
104 trampoline[pos++] = disasm.Instruction.Opcode + 1;
105 trampoline[pos++] = 5;
106 DDrPatch_MakeJump(&trampoline[pos], (void*)target);
107 pos += 5;
108 }
109 break;
110 // Opcode -1
111 case JNO:
112 case JNC:
113 case JNE:
114 case JA:
115 case JNS:
116 case JNP:
117 case JNL:
118 case JG:
119 if (targetInTrampoline) {
120 memcpy(&trampoline[pos], (void*)disasm.EIP, len);
121 pos += len;
122 } else {
123 trampoline[pos++] = disasm.Instruction.Opcode - 1;
124 trampoline[pos++] = 5;
125 DDrPatch_MakeJump(&trampoline[pos], (void*)target);
126 pos += 5;
127 }
128 break;
129 default:
130 STARTUPMESSAGE("Detour: Unknown branch in trampoline area from address 0x%08x", from);
131 return (void*)-1;
132 }
133 } else {
134 memcpy(&trampoline[pos], (void*)disasm.EIP, len);
135 pos += len;
136 }
137 disasm.EIP += (UIntPtr)len;
138 }
139 else {
140 STARTUPMESSAGE("Detour: Unknown opcode in trampoline area from address 0x%08x", from);
141 return (void*)-1;
142 }
143 }
144
145 if (branches > 1) {
146 STARTUPMESSAGE("Detour: Too many branches in trampoline'd code from address 0x%08x: %d", from, branches);
147 return (void*)-1;
148 }
149
150
151 DDrPatch_MakeJump(&trampoline[pos], (void*)disasm.EIP);
152 DDrPatch_NOOP(from, (void*)disasm.EIP - from);
153
154 DWORD oldp;
155 if (!VirtualProtect(trampoline, 40, PAGE_EXECUTE_READWRITE, &oldp)) {
156 STARTUPMESSAGE("Detour: Could not mark page for trampoline as executable: from address 0x%08x", from);
157 return (void*)-1;
158 }
159 DDrPatch_MakeJump(from, to);
160
161/*
162 STARTUPMESSAGE("Trampoline", 0);
163 DDrPatch_PrintDisasm(trampoline, 10, 6);
164
165 STARTUPMESSAGE("Orig after", 0);
166 DDrPatch_PrintDisasm(disasm.EIP, 7, 0);
167
168 STARTUPMESSAGE("Orig start after", 0);
169 DDrPatch_PrintDisasm(from, 3, 6);
170*/
171 return trampoline;
172}
173
174bool DDrPatch_String(char* dest, const unsigned char* string, int length)
175{
176 DWORD oldp;
177
178 if (VirtualProtect(dest, length, PAGE_EXECUTE_READWRITE, &oldp))
179 {
180 memcpy(dest, string, length);
181 VirtualProtect(dest, length, oldp, &oldp);
182 return true;
183 }
184 else
185 return false;
186}
187
188bool DDrPatch_Byte(char* dest, unsigned char value)
189{
190 DWORD oldp;
191
192 if (VirtualProtect(dest, 1, PAGE_EXECUTE_READWRITE, &oldp))
193 {
194 *dest = value;
195 VirtualProtect(dest, 1, oldp, &oldp);
196 return true;
197 }
198 else
199 return false;
200}
201
202bool DDrPatch_Int32(int* dest, unsigned int value)
203{
204 DWORD oldp;
205
206 if (VirtualProtect(dest, 4, PAGE_EXECUTE_READWRITE, &oldp))
207 {
208 *dest = value;
209 VirtualProtect(dest, 4, oldp, &oldp);
210 return true;
211 }
212 else
213 return false;
214}
215
216bool DDrPatch_Int16(short* dest, unsigned short value)
217{
218 DWORD oldp;
219
220 if (VirtualProtect(dest, 2, PAGE_EXECUTE_READWRITE, &oldp))
221 {
222 *dest = value;
223 VirtualProtect(dest, 2, oldp, &oldp);
224 return true;
225 }
226 else
227 return false;
228}
229
230bool DDrPatch_NOOP(char* dest, unsigned int length)
231{
232 DWORD oldp;
233
234 if (VirtualProtect(dest, length, PAGE_EXECUTE_READWRITE, &oldp))
235 {
236 memset(dest, 0x90, length);
237 VirtualProtect(dest, length, oldp, &oldp);
238 return true;
239 }
240 else
241 return false;
242}
243
244void* DDrPatch_ExecutableASM(char* from, char* nextInst, const unsigned char* code, int length)
245{
246 char* newCode = malloc(length+5);
247 if (!DDrPatch_NOOP(newCode, length+5))
248 return (void*)-1;
249
250 memcpy(newCode, code, length);
251 if (!DDrPatch_MakeJump(&newCode[length], nextInst))
252 return (void*)-1;
253
254 DWORD oldp;
255 if (!VirtualProtect(newCode, length+5, PAGE_EXECUTE_READWRITE, &oldp)) {
256 STARTUPMESSAGE("ExecASM: Could not mark page for new code as executable: from address 0x%08x", from);
257 return (void*)-1;
258 }
259
260 if (!DDrPatch_MakeJump(from, newCode))
261 return (void*)-1;
262
263 return newCode;
264}
265
266void DDrPatch_PrintDisasm(void* addr, int instLimit, int sizeLimit)
267{
268 DISASM MyDisasm;
269 int len = 0;
270 int size = 0;
271 int i = 0;
272
273 memset(&MyDisasm, 0, sizeof(DISASM));
274
275 MyDisasm.EIP = (UIntPtr) addr;
276
277 STARTUPMESSAGE("", 0);
278 STARTUPMESSAGE("Disassembly @ 0x%06x", addr);
279
280 if (sizeLimit <= 0)
281 sizeLimit = 20 * instLimit;
282
283 while ((i < instLimit) && (size < sizeLimit)) {
284 len = Disasm(&MyDisasm);
285 if (len != UNKNOWN_OPCODE) {
286 size += len;
287 STARTUPMESSAGE(" %s, Opcode: 0x%x, len: %d, branch: %d, to: 0x%06x", MyDisasm.CompleteInstr, MyDisasm.Instruction.Opcode, len, MyDisasm.Instruction.BranchType, MyDisasm.Instruction.AddrValue);
288 STARTUPMESSAGE(" Cat: 0x%04x, prefix count: %d", MyDisasm.Instruction.Category & 0xffff, MyDisasm.Prefix.Number );
289
290 MyDisasm.EIP += (UIntPtr)len;
291 i++;
292 }
293 };
294
295 STARTUPMESSAGE("", 0);
296}
297
Note: See TracBrowser for help on using the repository browser.