Skip to content

Instantly share code, notes, and snippets.

@mtijanic
Last active June 11, 2022 00:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mtijanic/e564e80931c2d15a991832f983877e03 to your computer and use it in GitHub Desktop.
Save mtijanic/e564e80931c2d15a991832f983877e03 to your computer and use it in GitHub Desktop.
Patch Linux nwmain to unlock selection of additional classes at character creation
// Released under WTFPL-2.0 license
//
// To compile:
// gcc -m32 -fPIC -shared -o nwmain-patch.so nwmain-patch.c
//
// To run, add nwmain-patch.so to LD_PRELOAD before running nwmain
// LD_PRELOAD=./nwmain-patch.so ; ./nwmain
#define _GNU_SOURCE 1
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/mman.h>
void nwmain_patch(void) __attribute__((constructor));
static void apply_patch(uintptr_t address, size_t patch_size, const uint8_t *patch)
{
uintptr_t page = address & ~0xFFF;
if (mprotect((void*)page, (address-page) + patch_size, PROT_WRITE | PROT_READ | PROT_EXEC))
{
perror("mprotect");
return;
}
printf("Applying patch at %p\n\tOld data:", (void*)address);
for (size_t i = 0; i < patch_size; i++)
printf(" %02x", ((uint8_t*)address)[i]);
printf("\n\tNew data:");
for (size_t i = 0; i < patch_size; i++)
printf(" %02x", patch[i]);
putchar('\n');
memcpy((void*)address, patch, patch_size);
}
void nwmain_patch(void)
{
//
// Old: 0f b6 05 fa e0 5f 08 movzx eax,BYTE PTR ds:0x85fe0fa
// New: b8 30 00 00 00 mov eax,0x30
// 90 nop
// 90 nop
//
// Code is trying to load the index of the Wizard class into EAX to
// use as a limit how many GUI listbox items to mark as enabled.
// Patch hardcodes this to 0x30 instead.
//
const uint8_t class_list_patch[] = {0xb8, 0x30, 0x00, 0x00, 0x00, 0x90, 0x90};
apply_patch(0x82320b0, sizeof(class_list_patch), class_list_patch);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment