Skip to content

Instantly share code, notes, and snippets.

@LordJZ
Created March 17, 2014 20:13
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 LordJZ/9607344 to your computer and use it in GitHub Desktop.
Save LordJZ/9607344 to your computer and use it in GitHub Desktop.
movement packet unpacker
#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
};
#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]);
#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