fixed chicken messages
[snoogans.git] / patch.c
blobec187511b142bf77ac13807c6fa5c192e84900b4
1 /*
2 * Copyright (C) 2010 gonzoj
4 * Please check the CREDITS file for further information.
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/mman.h>
24 #include <unistd.h>
26 #include "d2pointers.h"
27 #include "kernel32.h"
28 #include "maphack.h"
29 #include "misc.h"
30 #include "patch.h"
31 #include "stubs.h"
32 #include "types.h"
34 #include "debug.h"
36 #include "version.h"
38 #define PAGE_ALIGN(addr) (addr & ~0xfff)
40 char last_game_name[512];
42 unit_any *viewing_unit;
44 #define i386_CALL 0xE8
45 #define i386_JUMP 0xE9
47 typedef struct
49 unsigned char type;
50 const char *module;
51 vaddr offset;
52 size_t size;
53 void *func;
54 unsigned char *backup;
55 } hook;
57 #define N_HOOKS 8
59 hook
60 hooks[] =
63 #ifdef _VERSION_1_13 /* updated */
64 { i386_CALL, "D2Client.dll", 0x626FE, 5, draw_automap, NULL}, /* updated 0x6FB126FE */
65 { i386_JUMP, "D2Client.dll", 0xC3DB4, 6, draw_ingame_STUB, NULL}, /* updated 0x6FB73DB4 */
66 { i386_CALL, "D2Client.dll", 0x92366, 6, item_name_patch_STUB, NULL}, /* updated 0x6FB42366 */
67 { i386_CALL, "D2Multi.dll", 0x14D29, 5, next_game_name_patch, NULL}, /* updated 0x6F9E4D29 */
68 { i386_CALL, "D2Multi.dll", 0x14A0B, 5, next_game_name_patch, NULL}, /* updated 0x6F9E4A0B */
69 { i386_CALL, "D2Client.dll", 0x953E2, 6, view_inventory_patch_1, NULL}, /* updated 0x6FB453E2 */
70 { i386_CALL, "D2Client.dll", 0x94AB4, 6, view_inventory_patch_2, NULL}, /* updated 0x6FB44AB4 */
71 { i386_CALL, "D2Client.dll", 0x93A6F, 5, view_inventory_patch_3, NULL} /* updated 0x6FB43A6F */
73 #elif defined _VERSION_1_12 /* from McGod's mMap (modified) */
74 { i386_CALL, "D2Client.dll", 0x4063E, 5, draw_automap, NULL },
75 { i386_JUMP, "D2Client.dll", 0x90524, 6, draw_ingame_STUB, NULL },
76 { i386_CALL, "D2Client.dll", 0xAF242, 6, view_inventory_patch_1, NULL },
77 { i386_CALL, "D2Client.dll", 0xAE914, 6, view_inventory_patch_2, NULL },
78 { i386_CALL, "D2Client.dll", 0xAD93F, 5, view_inventory_patch_3, NULL },
79 { i386_CALL, "D2Client.dll", 0xAC236, 6, item_name_patch_STUB, NULL },
80 { i386_CALL, "D2Multi.dll", 0x14959, 5, next_game_name_patch, NULL },
81 { i386_CALL, "D2Multi.dll", 0x1463B, 5, next_game_name_patch, NULL }
83 #else
85 #error NO VERSION SPECIFIED
87 #endif
91 void
92 draw_automap()
94 reveal_automap();
95 draw_monsters();
96 draw_automap_text();
97 if (strlen(D2CLIENT_get_game_info()->game_ip) > 0)
99 draw_text(780, 122, D2FONT_GOLD, 0, D2FONT_SPECIAL, 0, "%s",
100 D2CLIENT_get_game_info()->game_ip);
104 void
105 draw_ingame()
107 draw_text(400, 540, D2FONT_WHITE, 0, D2FONT_STANDARD, 1, "%s",
108 "snoogans.so v 0.4");
111 void __attribute__((fastcall))
112 item_name_patch(unit_any *item, ms_wchar_t *wname)
114 if (!item || !wname)
116 return;
118 char tmp[512];
119 ms_wchar_to_char(wname, tmp);
120 char line1[512], *line2;
121 strcpy(line1, strtok(tmp, "\n"));
122 line2 = strtok(NULL, "\n");
123 int sockets = D2COMMON_get_unit_stat(item, 194, 0);
124 if (sockets > 0)
126 char c_sockets[5];
127 sprintf(c_sockets, " (%i)", sockets);
128 strcat(line1, c_sockets);
130 if (item->item_data->flags & 0x400000)
132 char eth[] = " (Eth)";
133 strcat(line1, eth);
135 char name[1024];
136 sprintf(name, "(%i) ", item->item_data->level);
137 strcat(name, line1);
138 if (line2)
140 strcat(name, "\n");
141 strcat(name, line2);
143 char_to_ms_wchar(name, wname);
146 void __attribute__((fastcall))
147 next_game_name_patch(vaddr box, int __attribute__((stdcall))
148 (*call_back)(vaddr, DWORD, DWORD))
150 if (strlen(last_game_name) == 0)
152 return;
154 ms_wchar_t wname[512];
155 char_to_ms_wchar(last_game_name, wname);
156 D2WIN_set_control_text(box, wname);
157 D2WIN_select_edit_box_text(box, wname);
158 D2WIN_set_edit_box_proc(box, call_back);
161 unit_any *
162 get_view_unit()
164 if (!viewing_unit)
166 return D2CLIENT_get_player_unit();
168 return viewing_unit;
171 unit_any *
172 view_inventory_patch()
174 unit_any *unit = get_view_unit();
175 unit_any *me = D2CLIENT_get_player_unit();
176 if (unit->id == me->id)
178 return me;
180 draw_text(560, 300, D2FONT_WHITE, 0, D2FONT_SPECIAL, 1, "%s",
181 unit->player_data->name);
182 return get_view_unit();
185 static int
186 install_hook(const char *module, vaddr offset, vaddr func, size_t bytes,
187 unsigned char inst, unsigned char **backup)
189 void *h = LoadLibraryA(module);
190 if (h == NULL)
192 printf("err: could not get a handle for %s\n", module);
193 return 0;
195 vaddr addr = (vaddr) h + offset;
196 unsigned char hook[bytes];
197 memset(hook, 0x90, bytes);
198 hook[0] = inst;
199 *(vaddr *) &hook[1] = func - (addr + 5);
200 DEBUG_DO(printf("installing hook at 0x%08X to func (0x%08X)\n", addr, func)); DEBUG_DO(printf("ASM: ");)
201 DEBUG_DO(inst == i386_CALL ? printf("call ") : printf("jmp ");)
202 DEBUG_DO(printf("0x%08X\n", func - (addr + 5));)
203 DEBUG_DO(printf("enabling write access to page(s) starting from 0x%08X\n", PAGE_ALIGN(addr));)
204 if (mprotect((void *) PAGE_ALIGN(addr), bytes, PROT_READ | PROT_WRITE
205 | PROT_EXEC))
207 printf("err: could not enable write access to page(s)\n");
208 return 0;
210 *backup = (unsigned char *) malloc(bytes);
211 memcpy((void *) *backup, (void *) addr, bytes);
212 DEBUG_DO(printf("saved original code\n");)
213 memcpy((void *) addr, (void *) hook, bytes);
214 DEBUG_DO(printf("patched to:\n");
215 int i;
216 for (i = 0; i < bytes; i++)
218 printf("0x%02X\n", hook[i]);
220 DEBUG_DO(printf("disabling write access to page(s) starting from 0x%08X\n", PAGE_ALIGN(addr));)
221 if (mprotect((void *) PAGE_ALIGN(addr), bytes, PROT_READ | PROT_EXEC))
223 printf("err: could not disable write access to page(s)\n");
224 return 0;
226 DEBUG_DO(printf("done\n");)
227 return 1;
231 install_hooks()
233 int i;
234 for (i = 0; i < N_HOOKS; i++)
236 if (!install_hook(hooks[i].module, hooks[i].offset,
237 (vaddr) hooks[i].func, hooks[i].size, hooks[i].type, &hooks[i].backup))
239 return 0;
242 return 1;
245 static int
246 remove_hook(const char *module, vaddr offset, size_t bytes,
247 unsigned char *backup)
249 void *h = LoadLibraryA(module);
250 if (h == NULL)
252 printf("err: could not get a handle for %s\n", module);
253 return 0;
255 vaddr addr = (vaddr) h + offset;
256 DEBUG_DO(printf("enabling write access to page(s) starting from 0x%08X\n", PAGE_ALIGN(addr));)
257 if (mprotect((void *) PAGE_ALIGN(addr), bytes, PROT_READ | PROT_WRITE
258 | PROT_EXEC))
260 printf("err: could not enable write access to page(s)\n");
261 return 0;
263 memcpy((void *) addr, (void *) backup, bytes);
264 DEBUG_DO(printf("restored original code:\n");
265 int i;
266 for (i = 0; i < bytes; i++)
268 printf("0x%02X\n", backup[i]);
270 free(backup);
271 DEBUG_DO(printf("disabling write access to page(s) starting from 0x%08X\n", PAGE_ALIGN(addr));)
272 if (mprotect((void *) PAGE_ALIGN(addr), bytes, PROT_READ | PROT_EXEC))
274 printf("err: could not disable write access to page(s)\n");
275 return 0;
277 DEBUG_DO(printf("done\n");)
278 return 1;
282 remove_hooks()
284 int i;
285 for (i = 0; i < N_HOOKS; i++)
287 if (hooks[i].backup)
289 if (!remove_hook(hooks[i].module, hooks[i].offset, hooks[i].size,
290 hooks[i].backup))
292 return 0;
296 return 1;