|
|
|
#include "Jit.h"
|
|
|
|
#include "RipXorInst.h"
|
|
|
|
#include "RipAndInst.h"
|
|
|
|
#include "RipOrInst.h"
|
|
|
|
#include "RipMovInst.h"
|
|
|
|
|
|
|
|
|
|
|
|
BOOL JitEmitPushfqInst(PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
UCHAR RawData[] = { 0x9C };
|
|
|
|
PNATIVE_CODE_LINK Link = new NATIVE_CODE_LINK(CODE_FLAG_IS_INST | CODE_FLAG_DO_NOT_DIVIDE, RawData, 1);
|
|
|
|
XedDecode(&Link->XedInstruction, Link->RawData, 1);
|
|
|
|
NcAppendToBlock(Block, Link);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL JitEmitPopfqInst(PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
UCHAR RawData[] = { 0x9D };
|
|
|
|
PNATIVE_CODE_LINK Link = new NATIVE_CODE_LINK(CODE_FLAG_IS_INST | CODE_FLAG_DO_NOT_DIVIDE, RawData, 1);
|
|
|
|
XedDecode(&Link->XedInstruction, Link->RawData, 1);
|
|
|
|
NcAppendToBlock(Block, Link);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL JitCheckFlagCollisions(CONST XED_FLAG_SET* FlagsRead, XED_FLAG_SET Ledger)
|
|
|
|
{
|
|
|
|
return ((FlagsRead->s.zf && FlagsRead->s.zf == Ledger.s.zf) ||
|
|
|
|
(FlagsRead->s.sf && FlagsRead->s.sf == Ledger.s.sf) ||
|
|
|
|
(FlagsRead->s.pf && FlagsRead->s.pf == Ledger.s.pf) ||
|
|
|
|
(FlagsRead->s.of && FlagsRead->s.of == Ledger.s.of) ||
|
|
|
|
(FlagsRead->s.cf && FlagsRead->s.cf == Ledger.s.cf) ||
|
|
|
|
(FlagsRead->s.af && FlagsRead->s.af == Ledger.s.af)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID JitUpdateConFlagsLedger(CONST XED_FLAG_SET* FlagsWritten, XED_FLAG_SET* Ledger)
|
|
|
|
{
|
|
|
|
if (FlagsWritten->s.zf)
|
|
|
|
Ledger->s.zf = FALSE;
|
|
|
|
if (FlagsWritten->s.sf)
|
|
|
|
Ledger->s.sf = FALSE;
|
|
|
|
if (FlagsWritten->s.pf)
|
|
|
|
Ledger->s.pf = FALSE;
|
|
|
|
if (FlagsWritten->s.of)
|
|
|
|
Ledger->s.of = FALSE;
|
|
|
|
if (FlagsWritten->s.cf)
|
|
|
|
Ledger->s.cf = FALSE;
|
|
|
|
if (FlagsWritten->s.af)
|
|
|
|
Ledger->s.af = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL JitDoesInstOverriteConditionFlags(PNATIVE_CODE_LINK Link)
|
|
|
|
{
|
|
|
|
CONST XED_SIMPLE_FLAG* SimpleFlags = XedDecodedInstGetRflagsInfo(&Link->XedInstruction);
|
|
|
|
CONST XED_FLAG_SET* FlagsWritten = XedSimpleFlagGetWrittenFlagSet(SimpleFlags);
|
|
|
|
CONST XED_FLAG_SET* FlagsUndefined = XedSimpleFlagGetUndefinedFlagSet(SimpleFlags);
|
|
|
|
|
|
|
|
return (FlagsWritten->s.zf &&
|
|
|
|
FlagsWritten->s.sf &&
|
|
|
|
FlagsWritten->s.pf &&
|
|
|
|
FlagsWritten->s.of &&
|
|
|
|
FlagsWritten->s.cf &&
|
|
|
|
FlagsUndefined->s.af
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL JitAreFlagsClobberedBeforeUse(PNATIVE_CODE_LINK Link)
|
|
|
|
{
|
|
|
|
XED_FLAG_SET Ledger;
|
|
|
|
Ledger.s.zf = TRUE;
|
|
|
|
Ledger.s.sf = TRUE;
|
|
|
|
Ledger.s.pf = TRUE;
|
|
|
|
Ledger.s.of = TRUE;
|
|
|
|
Ledger.s.cf = TRUE;
|
|
|
|
Ledger.s.af = TRUE;
|
|
|
|
|
|
|
|
for (PNATIVE_CODE_LINK T = Link->Next; T; T = T->Next)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
CONST XED_SIMPLE_FLAG* SimpleFlags = XedDecodedInstGetRflagsInfo(&T->XedInstruction);
|
|
|
|
CONST XED_FLAG_SET* FlagsRead = XedSimpleFlagGetReadFlagSet(SimpleFlags);
|
|
|
|
CONST XED_FLAG_SET* FlagsWritten = XedSimpleFlagGetWrittenFlagSet(SimpleFlags);
|
|
|
|
|
|
|
|
if (JitCheckFlagCollisions(FlagsRead, Ledger))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
JitUpdateConFlagsLedger(FlagsWritten, &Ledger);
|
|
|
|
|
|
|
|
if (Ledger.flat == 0)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID JitMutateInstForXor(PNATIVE_CODE_LINK Link, PJIT_BITWISE_DATA JitData)
|
|
|
|
{
|
|
|
|
ULONG FourByte = Link->RawDataSize / 4;
|
|
|
|
ULONG TwoByte = (Link->RawDataSize - (FourByte * 4)) / 2;
|
|
|
|
ULONG OneByte = (Link->RawDataSize - (FourByte * 4) - (TwoByte * 2));
|
|
|
|
|
|
|
|
PUCHAR Buffer = Link->RawData;
|
|
|
|
while (FourByte)
|
|
|
|
{
|
|
|
|
*(PULONG)Buffer ^= JitData->Data[2 - FourByte];
|
|
|
|
Buffer += 4;
|
|
|
|
FourByte--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TwoByte)
|
|
|
|
{
|
|
|
|
*(PUSHORT)Buffer ^= (USHORT)JitData->Data[3];
|
|
|
|
Buffer += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OneByte)
|
|
|
|
*(PUCHAR)Buffer ^= (UCHAR)JitData->Data[3];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID JitMutateInstForOr(PNATIVE_CODE_LINK Link, PJIT_BITWISE_DATA JitData)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID JitMutateInstForAnd(PNATIVE_CODE_LINK Link, PJIT_BITWISE_DATA JitData)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
PNATIVE_CODE_BLOCK JitEmitPreRipMov(PNATIVE_CODE_LINK Link, INT32 Delta)
|
|
|
|
{
|
|
|
|
ULONG FourByte = Link->RawDataSize / 4;
|
|
|
|
ULONG TwoByte = (Link->RawDataSize - (FourByte * 4)) / 2;
|
|
|
|
ULONG OneByte = (Link->RawDataSize - (FourByte * 4) - (TwoByte * 2));
|
|
|
|
|
|
|
|
PNATIVE_CODE_BLOCK Block = new NATIVE_CODE_BLOCK;
|
|
|
|
|
|
|
|
Block->Start = Block->End = new NATIVE_CODE_LINK;
|
|
|
|
PUCHAR DataOffset = Link->RawData;
|
|
|
|
ULONG Count = FourByte;
|
|
|
|
while (Count)
|
|
|
|
{
|
|
|
|
//Account for remaining MOVs
|
|
|
|
INT32 RipDelta = (((Count - 1) * DWORD_MOV_INST_LENGTH) + (TwoByte * WORD_MOV_INST_LENGTH) + (OneByte * BYTE_MOV_INST_LENGTH));
|
|
|
|
//Account for already MOVd instructions
|
|
|
|
RipDelta += ((FourByte - Count) * 4);
|
|
|
|
RipDelta += Delta;
|
|
|
|
//Add the actual instruction
|
|
|
|
if (!JitEmitRipRelativeMovD(Block, RipDelta, DataOffset))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
DataOffset += 4;
|
|
|
|
--Count;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TwoByte)
|
|
|
|
{
|
|
|
|
INT32 RipDelta = (OneByte * BYTE_MOV_INST_LENGTH);
|
|
|
|
RipDelta += (FourByte * 4);
|
|
|
|
RipDelta += Delta;
|
|
|
|
if (!JitEmitRipRelativeMovW(Block, RipDelta, DataOffset))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
DataOffset += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OneByte)
|
|
|
|
{
|
|
|
|
INT32 RipDelta = 0;
|
|
|
|
RipDelta += (FourByte * 4) + (TwoByte * 2);
|
|
|
|
RipDelta += Delta;
|
|
|
|
if (!JitEmitRipRelativeMovB(Block, RipDelta, DataOffset))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PNATIVE_CODE_LINK StartLink = Block->Start;
|
|
|
|
Block->Start = Block->Start->Next;
|
|
|
|
if (Block->Start)
|
|
|
|
Block->Start->Prev = NULL;
|
|
|
|
delete StartLink;
|
|
|
|
|
|
|
|
return Block;
|
|
|
|
}
|
|
|
|
|
|
|
|
PNATIVE_CODE_BLOCK JitEmitPostRipMov(PNATIVE_CODE_LINK Link, INT32 Delta)
|
|
|
|
{
|
|
|
|
ULONG FourByte = Link->RawDataSize / 4;
|
|
|
|
ULONG TwoByte = (Link->RawDataSize - (FourByte * 4)) / 2;
|
|
|
|
ULONG OneByte = (Link->RawDataSize - (FourByte * 4) - (TwoByte * 2));
|
|
|
|
|
|
|
|
PNATIVE_CODE_BLOCK Block = new NATIVE_CODE_BLOCK;
|
|
|
|
|
|
|
|
Block->Start = Block->End = new NATIVE_CODE_LINK;
|
|
|
|
ULONG ZeroValue = 0;
|
|
|
|
ULONG Count = FourByte;
|
|
|
|
while (Count)
|
|
|
|
{
|
|
|
|
INT32 RipDelta = Link->RawDataSize - ((FourByte - Count) * 4);
|
|
|
|
RipDelta += (FourByte - (Count - 1)) * DWORD_MOV_INST_LENGTH;
|
|
|
|
RipDelta *= (-1);
|
|
|
|
RipDelta += Delta;
|
|
|
|
ZeroValue = rand();
|
|
|
|
if (!JitEmitRipRelativeMovD(Block, RipDelta, (PUCHAR)&ZeroValue))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
--Count;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TwoByte)
|
|
|
|
{
|
|
|
|
INT32 RipDelta = Link->RawDataSize - (FourByte * 4);
|
|
|
|
RipDelta += (FourByte * DWORD_MOV_INST_LENGTH);
|
|
|
|
RipDelta += WORD_MOV_INST_LENGTH;
|
|
|
|
RipDelta *= (-1);
|
|
|
|
RipDelta += Delta;
|
|
|
|
ZeroValue = rand();
|
|
|
|
if (!JitEmitRipRelativeMovW(Block, RipDelta, (PUCHAR)&ZeroValue))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OneByte)
|
|
|
|
{
|
|
|
|
INT32 RipDelta = Link->RawDataSize - (FourByte * 4) - (TwoByte * 2);
|
|
|
|
RipDelta += (FourByte * DWORD_MOV_INST_LENGTH);
|
|
|
|
RipDelta += (TwoByte * WORD_MOV_INST_LENGTH);
|
|
|
|
RipDelta += BYTE_MOV_INST_LENGTH;
|
|
|
|
RipDelta *= (-1);
|
|
|
|
RipDelta += Delta;
|
|
|
|
ZeroValue = rand();
|
|
|
|
if (!JitEmitRipRelativeMovB(Block, RipDelta, (PUCHAR)&ZeroValue))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PNATIVE_CODE_LINK StartLink = Block->Start;
|
|
|
|
Block->Start = Block->Start->Next;
|
|
|
|
if (Block->Start)
|
|
|
|
Block->Start->Prev = NULL;
|
|
|
|
delete StartLink;
|
|
|
|
|
|
|
|
return Block;
|
|
|
|
}
|
|
|
|
|
|
|
|
INLINE BOOL JitiEmitWrapperD(ULONG OpType, PNATIVE_CODE_BLOCK Block, INT32 RipDelta, ULONG Value)
|
|
|
|
{
|
|
|
|
switch (OpType)
|
|
|
|
{
|
|
|
|
case JIT_BITWISE_XOR: return JitEmitRipRelativeXorD(Block, RipDelta, Value);
|
|
|
|
case JIT_BITWISE_AND: return JitEmitRipRelativeAndD(Block, RipDelta, Value);
|
|
|
|
case JIT_BITWISE_OR: return JitEmitRipRelativeOrD(Block, RipDelta, Value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
INLINE BOOL JitiEmitWrapperW(ULONG OpType, PNATIVE_CODE_BLOCK Block, INT32 RipDelta, ULONG Value)
|
|
|
|
{
|
|
|
|
switch (OpType)
|
|
|
|
{
|
|
|
|
case JIT_BITWISE_XOR: return JitEmitRipRelativeXorW(Block, RipDelta, Value);
|
|
|
|
case JIT_BITWISE_AND: return JitEmitRipRelativeAndW(Block, RipDelta, Value);
|
|
|
|
case JIT_BITWISE_OR: return JitEmitRipRelativeOrW(Block, RipDelta, Value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
INLINE BOOL JitiEmitWrapperB(ULONG OpType, PNATIVE_CODE_BLOCK Block, INT32 RipDelta, ULONG Value)
|
|
|
|
{
|
|
|
|
switch (OpType)
|
|
|
|
{
|
|
|
|
case JIT_BITWISE_XOR: return JitEmitRipRelativeXorB(Block, RipDelta, Value);
|
|
|
|
case JIT_BITWISE_AND: return JitEmitRipRelativeAndB(Block, RipDelta, Value);
|
|
|
|
case JIT_BITWISE_OR: return JitEmitRipRelativeOrB(Block, RipDelta, Value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PNATIVE_CODE_BLOCK JitEmitPreRipBitwiseOp(PNATIVE_CODE_LINK Link, PJIT_BITWISE_DATA JitData, ULONG OpType, BOOL SaveFlags, INT32 Delta)
|
|
|
|
{
|
|
|
|
ULONG FourByte = Link->RawDataSize / 4;
|
|
|
|
ULONG TwoByte = (Link->RawDataSize - (FourByte * 4)) / 2;
|
|
|
|
ULONG OneByte = (Link->RawDataSize - (FourByte * 4) - (TwoByte * 2));
|
|
|
|
|
|
|
|
PNATIVE_CODE_BLOCK Block = new NATIVE_CODE_BLOCK;
|
|
|
|
if (!Block)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (SaveFlags && !JitEmitPushfqInst(Block))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG Count = FourByte;
|
|
|
|
while (Count)
|
|
|
|
{
|
|
|
|
INT32 RipDelta = (((Count - 1) * DWORD_RIP_INST_LENGTH) + (TwoByte * WORD_RIP_INST_LENGTH) + (OneByte * BYTE_RIP_INST_LENGTH));
|
|
|
|
if (SaveFlags)
|
|
|
|
RipDelta += 1;
|
|
|
|
RipDelta += ((FourByte - Count) * 4);
|
|
|
|
RipDelta += Delta;
|
|
|
|
if (!JitiEmitWrapperD(OpType, Block, RipDelta, JitData->Data[FourByte - Count]))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
--Count;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TwoByte)
|
|
|
|
{
|
|
|
|
INT32 RipDelta = (OneByte * BYTE_RIP_INST_LENGTH);
|
|
|
|
if (SaveFlags)
|
|
|
|
RipDelta += 1;
|
|
|
|
RipDelta += (FourByte * 4);
|
|
|
|
RipDelta += Delta;
|
|
|
|
if (!JitiEmitWrapperW(OpType, Block, RipDelta, JitData->Data[3]))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OneByte)
|
|
|
|
{
|
|
|
|
INT32 RipDelta = 0;
|
|
|
|
if (SaveFlags)
|
|
|
|
RipDelta += 1;
|
|
|
|
RipDelta += (FourByte * 4) + (TwoByte * 2);
|
|
|
|
RipDelta += Delta;
|
|
|
|
if (!JitiEmitWrapperB(OpType, Block, RipDelta, JitData->Data[4]))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SaveFlags && !JitEmitPopfqInst(Block))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Block;
|
|
|
|
}
|
|
|
|
|
|
|
|
PNATIVE_CODE_BLOCK JitEmitPostRipBitwiseOp(PNATIVE_CODE_LINK Link, PJIT_BITWISE_DATA JitData, ULONG OpType, BOOL SaveFlags, INT32 Delta)
|
|
|
|
{
|
|
|
|
ULONG FourByte = Link->RawDataSize / 4;
|
|
|
|
ULONG TwoByte = (Link->RawDataSize - (FourByte * 4)) / 2;
|
|
|
|
ULONG OneByte = (Link->RawDataSize - (FourByte * 4) - (TwoByte * 2));
|
|
|
|
|
|
|
|
PNATIVE_CODE_BLOCK Block = new NATIVE_CODE_BLOCK;
|
|
|
|
if (!Block)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (SaveFlags && !JitEmitPushfqInst(Block))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG Count = FourByte;
|
|
|
|
while (Count)
|
|
|
|
{
|
|
|
|
INT32 RipDelta = Link->RawDataSize - ((FourByte - Count) * 4);
|
|
|
|
if (SaveFlags)
|
|
|
|
RipDelta += 1;
|
|
|
|
RipDelta += (FourByte - (Count - 1)) * DWORD_RIP_INST_LENGTH;
|
|
|
|
RipDelta *= (-1);
|
|
|
|
RipDelta += Delta;
|
|
|
|
if (!JitiEmitWrapperD(OpType, Block, RipDelta, JitData->Data[FourByte - Count]))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
--Count;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TwoByte)
|
|
|
|
{
|
|
|
|
INT32 RipDelta = Link->RawDataSize - (FourByte * 4);
|
|
|
|
if (SaveFlags)
|
|
|
|
RipDelta += 1;
|
|
|
|
RipDelta += (FourByte * DWORD_RIP_INST_LENGTH);
|
|
|
|
RipDelta += WORD_RIP_INST_LENGTH;
|
|
|
|
RipDelta *= (-1);
|
|
|
|
RipDelta += Delta;
|
|
|
|
if (!JitiEmitWrapperW(OpType, Block, RipDelta, JitData->Data[3]))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OneByte)
|
|
|
|
{
|
|
|
|
INT32 RipDelta = Link->RawDataSize - (FourByte * 4) - (TwoByte * 2);
|
|
|
|
if (SaveFlags)
|
|
|
|
RipDelta += 1;
|
|
|
|
RipDelta += (FourByte * DWORD_RIP_INST_LENGTH);
|
|
|
|
RipDelta += WORD_RIP_INST_LENGTH;
|
|
|
|
RipDelta += BYTE_RIP_INST_LENGTH;
|
|
|
|
RipDelta *= (-1);
|
|
|
|
RipDelta += Delta;
|
|
|
|
if (!JitiEmitWrapperB(OpType, Block, RipDelta, JitData->Data[4]))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SaveFlags && !JitEmitPopfqInst(Block))
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Block;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Block;
|
|
|
|
}
|