Created
March 17, 2014 20:13
-
-
Save LordJZ/9607344 to your computer and use it in GitHub Desktop.
movement packet unpacker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
#include "MovementStatus.h" | |
int __stdcall IDAP_init(void) | |
{ | |
// "metapc" represents x86 architecture | |
if (strncmp(inf.procName, "metapc", 8) != 0) | |
{ | |
error("Only PE and ELF binary type compiled for the x86 platform is supported, sorry."); | |
return PLUGIN_SKIP; | |
} | |
return PLUGIN_OK; | |
} | |
void __stdcall IDAP_term(void) | |
{ | |
// Stuff to do when exiting, generally you'd put any sort | |
// of clean-up jobs here. | |
return; | |
} | |
// Actually checks if the value stores boolean if itself should be read | |
bool __stdcall isGuidStr(const char* str) | |
{ | |
int len = strlen(str); | |
#ifdef IS_4_3_CLIENT | |
return strcmp(str, "PositionO") == 0 | |
|| strcmp(str, "SplineElev") == 0 | |
|| strcmp(str, "Pitch") == 0 | |
|| strcmp(str, "Timestamp") == 0 | |
|| memcmp(str, "Flags", 5) == 0 | |
|| memcmp(str + len - 5, "Byte", 4) == 0; | |
#else | |
return memcmp(str + len - 5, "Byte", 4) == 0; | |
#endif | |
} | |
void unpackrecv() | |
{ | |
ea_t addr = get_screen_ea(); | |
int insn_size; | |
uint16 reg = 1; // ecx | |
uint16 altReg = -1; | |
int altDDisp = 0; | |
bool regRebased = false; | |
char* gotData = new char[MovementStatus::ElementCount]; | |
memset(gotData, 0, MovementStatus::ElementCount * sizeof(char)); | |
if (decode_insn(addr)) | |
{ | |
msg("Current instruction: type=%u\n", cmd.itype); | |
msg(" Op1: type=%u phrase=%u addr=%u value=%u\n", cmd.Op1.type, cmd.Op1.phrase, cmd.Op1.addr, cmd.Op1.value); | |
msg(" Op2: type=%u phrase=%u addr=%u value=%u\n", cmd.Op2.type, cmd.Op2.phrase, cmd.Op2.addr, cmd.Op2.value); | |
} | |
while ((insn_size = decode_insn(addr)) != 0) | |
{ | |
int disp = -1; | |
if (cmd.itype == NN_int3) | |
{ | |
insn_size = 0; | |
break; | |
} | |
else if (cmd.itype == NN_mov) | |
{ | |
op_t& op1 = cmd.Op1; | |
op_t& op2 = cmd.Op2; | |
if (op2.type == o_reg && op2.reg == reg && op1.type == o_reg) | |
{ | |
msg("%a: rebasing reg %u -> %u\n", addr, op2.reg, op1.reg); | |
reg = op1.reg; | |
if (regRebased) | |
msg("ERROR: %a: reg already rebased\n", addr); | |
else | |
regRebased = true; | |
goto cont; | |
} | |
} | |
// fill alt reg | |
if (cmd.itype == NN_lea && cmd.Op1.type == o_reg && cmd.Op2.type == o_displ && cmd.Op2.phrase == reg) | |
{ | |
altReg = cmd.Op1.reg; | |
altDDisp = cmd.Op2.addr; | |
if (altDDisp < 16) | |
{ | |
msg("ERROR: %a: Too small delta disp (%u)\n", addr, altDDisp); | |
altReg = -1; | |
goto cont; | |
} | |
altDDisp -= 16; | |
//msg("%a: filled alt reg (%u) to disp %u\n", addr, altReg, altDDisp); | |
goto cont; | |
} | |
// fill alt reg from alt reg | |
if (cmd.itype == NN_lea && cmd.Op1.type == o_reg && cmd.Op2.type == o_displ && cmd.Op2.phrase == altReg) | |
{ | |
altReg = cmd.Op1.reg; | |
altDDisp = cmd.Op2.addr + altDDisp; | |
//msg("%a: filled alt reg (%u) from alt reg to disp %u\n", addr, altReg, altDDisp); | |
goto cont; | |
} | |
// drop alt reg | |
if ((cmd.itype == NN_lea || cmd.itype == NN_mov) && cmd.Op1.type == o_reg) | |
{ | |
if (cmd.Op1.reg == altReg) | |
altReg = -1; | |
else if (cmd.Op1.reg == reg) | |
{ | |
msg("ERROR: %a: current reg overwritten\n", addr); | |
break; | |
} | |
goto cont; | |
} | |
// inc alt reg | |
if (cmd.itype == NN_add && cmd.Op1.type == o_reg && cmd.Op1.reg == altReg && cmd.Op2.type == o_imm) | |
{ | |
altDDisp += cmd.Op2.value; | |
goto cont; | |
} | |
// push alt reg | |
if (cmd.itype == NN_push && cmd.Op1.type == o_reg && cmd.Op1.reg == altReg) | |
{ | |
//msg("%a: push altReg\n", addr); | |
disp = altDDisp; | |
goto foundDisp; | |
} | |
if ((cmd.itype == NN_mov || cmd.itype == NN_cmp || cmd.itype == NN_lea || cmd.itype == NN_movss) && | |
((cmd.Op1.type == o_displ && (disp = cmd.Op1.addr)) || (cmd.Op1.type == o_phrase && cmd.Op1.phrase == altReg && !(disp = cmd.Op1.addr)))) | |
{ | |
msg("%a: got mov/cmp/lea/movss ; reg=%u altReg=%u", addr, reg, altReg); | |
if (cmd.Op1.phrase == reg) | |
{ | |
if (disp < 16) | |
{ | |
msg("ERROR: %a: Too small disp (%u)\n", addr, disp); | |
goto cont; | |
} | |
disp -= 16; | |
goto foundDisp; | |
} | |
else if (cmd.Op1.phrase == altReg) | |
{ | |
disp += altDDisp; | |
goto foundDisp; | |
} | |
} | |
if (false) | |
{ | |
foundDisp: | |
if (disp >= MovementStatus::ElementCount) | |
{ | |
msg("%a: Too big disp (16+%u)\n", addr, disp); | |
goto cont; | |
} | |
const char* name = MovementStatus::ElementNames[disp]; | |
if (!name) | |
{ | |
msg("%a: Unknown element (16+%u)\n", addr, disp); | |
goto cont; | |
} | |
char* p = ""; | |
if (gotData[disp] == 0 || (gotData[disp] == 1 && isGuidStr(name) && (p = "_2"))) | |
{ | |
msg("MovementStatusElements.%s%s, // %a\n", name, p, addr); | |
++gotData[disp]; | |
} | |
} | |
cont: | |
addr += insn_size; | |
} | |
delete[] gotData; | |
} | |
void unpacksend() | |
{ | |
ea_t addr = get_screen_ea(); | |
int insn_size; | |
char* gotData = new char[MovementStatus::ElementCount]; | |
memset(gotData, 0, MovementStatus::ElementCount * sizeof(char)); | |
if (decode_insn(addr)) | |
{ | |
msg("Current instruction: type=%u\n", cmd.itype); | |
msg(" Op1: type=%u phrase=%u addr=%u value=%u\n", cmd.Op1.type, cmd.Op1.phrase, cmd.Op1.addr, cmd.Op1.value); | |
msg(" Op2: type=%u phrase=%u addr=%u value=%u\n", cmd.Op2.type, cmd.Op2.phrase, cmd.Op2.addr, cmd.Op2.value); | |
} | |
int regs[32]; | |
for (int i = 0; i < sizeof(regs)/sizeof(regs[0]); ++i) | |
regs[i] = -1; | |
regs[1] = 0; // ecx | |
int pushedDisp = -1; | |
while ((insn_size = decode_insn(addr)) != 0) | |
{ | |
int disp = -1; | |
if (cmd.itype == NN_int3) | |
{ | |
insn_size = 0; | |
break; | |
} | |
if (cmd.itype == NN_mov || cmd.itype == NN_movzx || cmd.itype == NN_lea || cmd.itype == NN_movss) | |
{ | |
op_t& op1 = cmd.Op1; | |
op_t& op2 = cmd.Op2; | |
if (cmd.itype != NN_movss && op1.type == o_reg) | |
{ | |
if (op2.type == o_reg || op2.type == o_phrase || op2.type == o_displ) | |
{ | |
if (regs[op2.phrase] == -1) | |
{ | |
regs[op1.reg] = -1; | |
//msg("%a: point 5, %u\n", addr, op2.reg); | |
} | |
else if (op1.reg >= 8) | |
{ | |
disp = regs[op2.phrase] + op2.addr - 16; | |
//msg("%a: point 4, %u %u %u\n", addr, disp, op2.phrase, op2.addr); | |
goto foundDisp; | |
} | |
else | |
{ | |
//msg("%a: point 3, %u %u %u\n", addr, op1.reg, op2.phrase, op2.addr); | |
regs[op1.reg] = regs[op2.phrase] + op2.addr; | |
} | |
} | |
else | |
{ | |
//msg("%a: point 2, %u\n", addr, op1.reg); | |
regs[op1.reg] = -1; | |
} | |
goto cont; | |
} | |
else if ((op1.type == o_phrase || op1.type == o_displ) && regs[op1.phrase] != -1) | |
{ | |
disp = regs[op1.phrase] + op1.addr - 16; | |
//msg("%a: point 1\n", addr); | |
goto foundDisp; | |
} | |
} | |
if (cmd.itype == NN_push) | |
{ | |
if (cmd.Op1.type == o_reg && regs[cmd.Op1.reg] != -1) | |
{ | |
if (pushedDisp >= 0) | |
msg("ERROR: Some shit with pushes at %a\n", addr); | |
pushedDisp = regs[cmd.Op1.reg] - 16; | |
//msg("%a: point 6, %u\n", addr, cmd.Op1.reg); | |
goto cont; | |
} | |
} | |
if (cmd.itype == NN_call && pushedDisp >= 0) | |
{ | |
disp = pushedDisp; | |
//msg("%a: point 7, %u\n", addr, pushedDisp); | |
pushedDisp = -1; | |
goto foundDisp; | |
} | |
if (cmd.itype == NN_cmp) | |
{ | |
op_t& op1 = cmd.Op1; | |
if ((op1.type == o_displ || op1.type == o_phrase) && regs[op1.phrase] != -1) | |
{ | |
disp = regs[op1.phrase] + op1.addr - 16; | |
//msg("%a: point 7, %u %u\n", addr, op1.phrase, op1.addr); | |
goto foundDisp; | |
} | |
} | |
if (cmd.itype == NN_add) | |
{ | |
if (cmd.Op1.type == o_reg && regs[cmd.Op1.reg] != -1 && cmd.Op2.type == o_imm) | |
{ | |
regs[cmd.Op1.reg] += cmd.Op2.value; | |
//msg("%a: point 8, %u\n", addr, cmd.Op2.value); | |
goto cont; | |
} | |
} | |
if (cmd.itype == NN_fld) | |
{ | |
// IDA emulates fld Op1 as st0 with type == 17 | |
op_t& op2 = cmd.Op2; | |
if ((op2.type == o_phrase || op2.type == o_displ) && regs[op2.phrase] != -1) | |
{ | |
disp = regs[op2.phrase] + op2.addr - 16; | |
//msg("%a: point 9, %u %u\n", addr, op2.phrase, op2.addr); | |
goto foundDisp; | |
} | |
} | |
if (cmd.itype == NN_or) | |
{ | |
if (cmd.Op1.type == o_reg && cmd.Op2.type == o_displ && regs[cmd.Op2.phrase] != -1) | |
{ | |
disp = regs[cmd.Op2.phrase] + cmd.Op2.addr - 16; | |
//msg("%a: point A, %u %u\n", addr, cmd.Op2.phrase, cmd.Op2.addr); | |
goto foundDisp; | |
} | |
} | |
while (false) | |
{ | |
foundDisp: | |
if (disp >= MovementStatus::ElementCount) | |
{ | |
msg("%a: Too big disp (%d+16)\n", addr, disp); | |
goto cont; | |
} | |
if (disp < 0) | |
{ | |
msg("%a: Too small disp (%d+16)\n", addr, disp); | |
goto cont; | |
} | |
const char* name = MovementStatus::ElementNames[disp]; | |
if (!name) | |
{ | |
msg("%a: Unknown element (%d+16)\n", addr, disp); | |
goto cont; | |
} | |
char* p = ""; | |
if (gotData[disp] == 0 || (gotData[disp] == 1 && isGuidStr(name) && (p = "_2"))) | |
{ | |
msg("MovementStatusElements.%s%s, // %a\n", name, p, addr); | |
++gotData[disp]; | |
} | |
} | |
cont: | |
addr += insn_size; | |
} | |
delete[] gotData; | |
} | |
// The plugin can be passed an integer argument from the plugins.cfg | |
// file. This can be useful when you want the one plug-in to do | |
// something different depending on the hot-key pressed or menu | |
// item selected. | |
void __stdcall IDAP_run(int isRecv) | |
{ | |
msg("Buzzle Movement Unpacker\n"); | |
msg("IsRecv = %d\n", isRecv); | |
if (isRecv) | |
unpackrecv(); | |
else | |
unpacksend(); | |
} | |
// There isn't much use for these yet, but I set them anyway. | |
char IDAP_comment[] = "Unpacks mov"; | |
char IDAP_help[] = "Buzzle Movement Unpacker"; | |
// The name of the plug-in displayed in the Edit->Plugins menu. It can | |
// be overridden in the user's plugins.cfg file. | |
char IDAP_name[] = "Buzzle Movement Unpacker"; | |
// The hot-key the user can use to run your plug-in. | |
char IDAP_hotkey[] = ""; | |
// The all-important exported PLUGIN object | |
plugin_t PLUGIN = | |
{ | |
IDP_INTERFACE_VERSION, // IDA version plug-in is written for | |
PLUGIN_UNL, // Flags (see below) | |
IDAP_init, // Initialisation function | |
IDAP_term, // Clean-up function | |
IDAP_run, // Main plug-in body | |
IDAP_comment, // Comment – unused | |
IDAP_help, // As above – unused | |
IDAP_name, // Plug-in name shown in | |
// Edit->Plugins menu | |
IDAP_hotkey // Hot key to run the plug-in | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
#include "MovementStatus.h" | |
#define EL_DWORD(NAME) NAME, NULL, NULL, NULL | |
#define EL_WORD(NAME) NAME, NULL | |
#define EL_BYTE(NAME) NAME | |
#define EL_GUID(NAME) NAME "Byte0", NAME "Byte1", NAME "Byte2", NAME "Byte3", \ | |
NAME "Byte4", NAME "Byte5", NAME "Byte6", NAME "Byte7" | |
const char* MovementStatus::ElementNames[] = | |
{ | |
#ifdef IS_4_3_CLIENT | |
EL_GUID("Guid"), | |
EL_DWORD("Flags"), | |
EL_DWORD("Flags2"), | |
EL_DWORD("Timestamp"), | |
EL_DWORD("PositionX"), EL_DWORD("PositionY"), EL_DWORD("PositionZ"), EL_DWORD("PositionO"), | |
EL_DWORD(NULL), | |
EL_DWORD("HaveTransportData"), | |
EL_DWORD(NULL), | |
EL_GUID("TransportGuid"), | |
EL_DWORD("TransportPositionX"), EL_DWORD("TransportPositionY"), EL_DWORD("TransportPositionZ"), EL_DWORD("TransportPositionO"), | |
EL_DWORD("TransportSeat"), | |
EL_DWORD("TransportTime"), | |
EL_DWORD("TransportHaveTime2"), | |
EL_DWORD("TransportTime2"), | |
EL_DWORD("TransportHaveTime3"), | |
EL_DWORD("TransportTime3"), | |
EL_DWORD("Pitch"), | |
EL_DWORD("HaveFallData"), | |
EL_DWORD("FallTime"), | |
EL_DWORD("FallVerticalSpeed"), | |
EL_DWORD("HaveFallDirection"), | |
EL_DWORD("FallCosAngle"), | |
EL_DWORD("FallSinAngle"), | |
EL_DWORD("FallHorizontalSpeed"), | |
EL_DWORD("SplineElev"), | |
EL_BYTE("HaveSpline"), | |
EL_BYTE("HaveSpline2"), | |
EL_WORD(NULL), | |
EL_DWORD("GenericDword0"), | |
EL_DWORD("GenericDword1"), | |
EL_DWORD("GenericDword2"), | |
EL_DWORD("GenericDword3"), | |
#else | |
EL_GUID("Guid"), | |
EL_DWORD("Flags"), | |
EL_DWORD("Flags2"), | |
EL_DWORD("Timestamp"), | |
EL_DWORD("PositionX"), EL_DWORD("PositionY"), EL_DWORD("PositionZ"), EL_DWORD("PositionO"), | |
EL_DWORD(NULL), | |
EL_DWORD("HaveTransportData"), | |
EL_DWORD(NULL), | |
EL_GUID("TransportGuid"), | |
EL_DWORD("TransportPositionX"), EL_DWORD("TransportPositionY"), EL_DWORD("TransportPositionZ"), EL_DWORD("TransportPositionO"), | |
EL_DWORD("TransportSeat"), | |
EL_DWORD("TransportTime"), | |
EL_DWORD("TransportHaveTime2"), | |
EL_DWORD("TransportTime2"), | |
EL_DWORD("TransportHaveTime3"), | |
EL_DWORD("TransportTime3"), | |
EL_DWORD("HavePitch"), | |
EL_DWORD("Pitch"), | |
EL_DWORD("HaveFallData"), | |
EL_DWORD("FallTime"), | |
EL_DWORD("FallVerticalSpeed"), | |
EL_DWORD("HaveFallDirection"), | |
EL_DWORD("FallCosAngle"), | |
EL_DWORD("FallSinAngle"), | |
EL_DWORD("FallHorizontalSpeed"), | |
EL_DWORD("HaveSplineElev"), | |
EL_DWORD("SplineElev"), | |
EL_DWORD("HaveSpline"), | |
EL_DWORD("GenericDword0"), | |
EL_DWORD("GenericDword1"), | |
EL_DWORD("GenericDword2"), | |
EL_DWORD("GenericDword3"), | |
#endif | |
}; | |
const int MovementStatus::ElementCount = sizeof(MovementStatus::ElementNames)/sizeof(MovementStatus::ElementNames[0]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
class MovementStatus | |
{ | |
public: | |
static const char* ElementNames[]; | |
static const int ElementCount; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment