DynamoRIO is a dynamic binary instrumentation framework. What that is exactly is explained, for example, here far better than I could, so I won't try. However, it's quite awesome and can be used in all the shady ways you can imagine. I choose unlocking protected lua functions for simplicity.
After a few minutes reversing we can say that if eax after the instruction at 0x53028 (0-based) would be 0 there would be no taint anymore and therefore all lua functions available. We could simply replace it with xox eax,eax or mov eax,0 and would be done. However odds are this offset is watched by their anti cheat system and so are all the other interesting offsets. And if not they will be, once they used in public. Usually we would now go to dissect their anti cheat measures and disable them.
DynamoRIO however gives us another option by letting us change the code flow while executing unnoticed by the application. In fact DynamoRIO is very determined about hiding changes which they call client transparency. The code is pretty much self explaining and if you have questions first read the documentation.
Code:
#define WINDOWS
#define X86_32
#include "dr_api.h"
static app_pc patch_addr = 0;
static void event_exit(void);
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating);
DR_EXPORT void dr_init(client_id_t id)
{
module_data_t *module;
if (patch_addr == 0) {
module = dr_lookup_module_by_name("Wow.exe");
if (module != NULL) {
patch_addr = module->start+0x53028;
}
dr_free_module_data(module);
}
// register events
dr_register_bb_event(event_basic_block);
dr_register_exit_event(event_exit);
}
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
// check if bb includes addr
if (instr_get_app_pc(instrlist_first(bb)) <= patch_addr && (instr_get_app_pc(instrlist_last(bb)) >= patch_addr)) {
/* iterate over instructions */
instr_t *instr;
for (instr = instrlist_first(bb); instr != NULL; instr = instr_get_next(instr)) {
if (instr_get_app_pc(instr) == patch_addr) {
instrlist_meta_postinsert(bb, instr, INSTR_CREATE_xor(drcontext, opnd_create_reg(DR_REG_XAX), opnd_create_reg(DR_REG_XAX)));
}
}
}
return DR_EMIT_DEFAULT;
}
static void event_exit(void)
{
/* empty */
}
I attached the code, the compiled binary, a compile script and a run script.
You have to download DynamoRIO and change the scripts depending on your location.
Some notes:
DynamoRIO is very well optimized but still a certain overhead remains. While I couldn't notice a slowdown this can be different for you.
Be aware this will prevent Wow detecting your patch. But any useful patch, including this, alters the behavior of the application and this change in behavior is still detectable. For instance, the application could invoke the patched routine with certain input knowing that the value at some memory location now, thanks to our patch, happens to be 0 should be something else given their input. I don't know if blizzard practices such behavior verification, but they could, so never feel too certain.
I should have mentioned it only allows execution per /dump macro.