|
|
|
#include "NativeCode.h"
|
|
|
|
#include "Random.h"
|
|
|
|
|
|
|
|
_NATIVE_CODE_LINK::_NATIVE_CODE_LINK()
|
|
|
|
{
|
|
|
|
XedDecodedInstZeroSetMode(&XedInstruction, &XedGlobalMachineState);
|
|
|
|
Flags = 0UL;
|
|
|
|
Next = Prev = NULL;
|
|
|
|
Block = NULL;
|
|
|
|
Label = 0UL;
|
|
|
|
RawData = NULL;
|
|
|
|
RawDataSize = 0UL;
|
|
|
|
AsmOperations.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
_NATIVE_CODE_LINK::_NATIVE_CODE_LINK(UINT LabelId, _NATIVE_CODE_BLOCK* B)
|
|
|
|
: _NATIVE_CODE_LINK()
|
|
|
|
{
|
|
|
|
Block = B;
|
|
|
|
Label = LabelId;
|
|
|
|
Flags = CODE_FLAG_IS_LABEL;
|
|
|
|
}
|
|
|
|
|
|
|
|
_NATIVE_CODE_LINK::_NATIVE_CODE_LINK(UINT F, PVOID Rd, UINT Rds, BOOL Decode)
|
|
|
|
: _NATIVE_CODE_LINK()
|
|
|
|
{
|
|
|
|
Flags = F;
|
|
|
|
RawDataSize = Rds;
|
|
|
|
RawData = new UCHAR[Rds];
|
|
|
|
if (Rd)
|
|
|
|
{
|
|
|
|
RtlCopyMemory(RawData, Rd, Rds);
|
|
|
|
if (Decode)
|
|
|
|
XedDecode(&XedInstruction, RawData, RawDataSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_NATIVE_CODE_LINK::~_NATIVE_CODE_LINK()
|
|
|
|
{
|
|
|
|
if (RawData)
|
|
|
|
delete[] RawData;
|
|
|
|
|
|
|
|
for (STDPAIR<FN_INST_ASM_OP, PVOID> CONST& Op : AsmOperations)
|
|
|
|
{
|
|
|
|
if (Op.second)
|
|
|
|
delete[] Op.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_NATIVE_CODE_BLOCK::_NATIVE_CODE_BLOCK()
|
|
|
|
{
|
|
|
|
Start = End = NULL;
|
|
|
|
LabelIds.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID NcAppendToBlock(PNATIVE_CODE_BLOCK Block, PNATIVE_CODE_LINK Link)
|
|
|
|
{
|
|
|
|
if (!Link)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Link->Block = Block;
|
|
|
|
Link->Prev = Block->End;
|
|
|
|
Link->Next = NULL;
|
|
|
|
|
|
|
|
if (!Block->End || !Block->Start)
|
|
|
|
{
|
|
|
|
Block->Start = Block->End = Link;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Block->End->Next = Link;
|
|
|
|
Block->End = Link;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID NcPrependToBlock(PNATIVE_CODE_BLOCK Block, PNATIVE_CODE_LINK Link)
|
|
|
|
{
|
|
|
|
if (!Link)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Link->Block = Block;
|
|
|
|
Link->Next = Block->Start;
|
|
|
|
Link->Prev = NULL;
|
|
|
|
|
|
|
|
if (!Block->End || !Block->Start)
|
|
|
|
{
|
|
|
|
Block->Start = Block->End = Link;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Block->Start->Prev = Link;
|
|
|
|
Block->Start = Link;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID NcInsertLinkAfter(PNATIVE_CODE_LINK Link1, PNATIVE_CODE_LINK Link2)
|
|
|
|
{
|
|
|
|
if (Link1)
|
|
|
|
{
|
|
|
|
Link2->Prev = Link1;
|
|
|
|
Link2->Next = Link1->Next;
|
|
|
|
Link1->Next = Link2;
|
|
|
|
if (Link2->Next)
|
|
|
|
Link2->Next->Prev = Link2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID NcInsertLinkBefore(PNATIVE_CODE_LINK Link1, PNATIVE_CODE_LINK Link2)
|
|
|
|
{
|
|
|
|
if (Link1)
|
|
|
|
{
|
|
|
|
Link2->Next = Link1;
|
|
|
|
Link2->Prev = Link1->Prev;
|
|
|
|
Link1->Prev = Link2;
|
|
|
|
if (Link2->Prev)
|
|
|
|
Link2->Prev->Next = Link2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID NcUnlink(PNATIVE_CODE_LINK Link)
|
|
|
|
{
|
|
|
|
if (Link)
|
|
|
|
{
|
|
|
|
if (Link->Next)
|
|
|
|
Link->Next->Prev = Link->Prev;
|
|
|
|
if (Link->Prev)
|
|
|
|
Link->Prev->Next = Link->Next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT NcCountInstructions(PNATIVE_CODE_BLOCK Block, BOOL CountCombinedAsOne)
|
|
|
|
{
|
|
|
|
UINT InstructionCount = 0;
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
continue;
|
|
|
|
if (CountCombinedAsOne && (T->Flags & CODE_FLAG_DO_NOT_DIVIDE) && !(T->Flags & CODE_FLAG_GROUP_END))
|
|
|
|
continue;
|
|
|
|
++InstructionCount;
|
|
|
|
}
|
|
|
|
return InstructionCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT NcCalcBlockSizeInBytes(PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
UINT TotalSize = 0;
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
continue;
|
|
|
|
TotalSize += T->RawDataSize;
|
|
|
|
}
|
|
|
|
return TotalSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT NcGenUnusedLabelId(PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
UINT ReturnLabelId = rand();
|
|
|
|
while (StdFind(Block->LabelIds.begin(), Block->LabelIds.end(), ReturnLabelId) != Block->LabelIds.end())
|
|
|
|
ReturnLabelId = rand();
|
|
|
|
Block->LabelIds.push_back(ReturnLabelId);
|
|
|
|
return ReturnLabelId;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID NcChangeLabelId(PNATIVE_CODE_BLOCK Block, UINT Original, UINT New)
|
|
|
|
{
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
|
|
|
|
{
|
|
|
|
if (((T->Flags & CODE_FLAG_IS_LABEL) || (T->Flags & CODE_FLAG_IS_REL_JMP)) && T->Label == Original)
|
|
|
|
T->Label = New;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID NcFixLabelsForBlocks(PNATIVE_CODE_BLOCK Block1, PNATIVE_CODE_BLOCK Block2)
|
|
|
|
{
|
|
|
|
for (PNATIVE_CODE_LINK T = Block2->Start; T && T != Block2->End->Next; T = T->Next)
|
|
|
|
{
|
|
|
|
if ((T->Flags & CODE_FLAG_IS_LABEL) && StdFind(Block1->LabelIds.begin(), Block1->LabelIds.end(), T->Label) != Block1->LabelIds.end())
|
|
|
|
{
|
|
|
|
NcChangeLabelId(Block2, T->Label, NcGenUnusedLabelId(Block1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcInsertBlockAfter(PNATIVE_CODE_LINK Link, PNATIVE_CODE_BLOCK Block, BOOL FixLabels)
|
|
|
|
{
|
|
|
|
if (!Link || !Link->Block || !Block || !Block->Start || !Block->End || Link->Block == Block)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (FixLabels && Block->LabelIds.size() && Link->Block->LabelIds.size())
|
|
|
|
NcFixLabelsForBlocks(Link->Block, Block);
|
|
|
|
|
|
|
|
if (Link->Next)
|
|
|
|
Link->Next->Prev = Block->End;
|
|
|
|
Block->End->Next = Link->Next;
|
|
|
|
Block->Start->Prev = Link;
|
|
|
|
Link->Next = Block->Start;
|
|
|
|
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
|
|
|
|
T->Block = Link->Block;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcInsertBlockBefore(PNATIVE_CODE_LINK Link, PNATIVE_CODE_BLOCK Block, BOOL FixLabels)
|
|
|
|
{
|
|
|
|
if (!Link || !Link->Block || !Block || !Block->Start || !Block->End)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (FixLabels && Block->LabelIds.size() && Link->Block->LabelIds.size())
|
|
|
|
NcFixLabelsForBlocks(Link->Block, Block);
|
|
|
|
|
|
|
|
if (Link->Prev)
|
|
|
|
Link->Prev->Next = Block->Start;
|
|
|
|
Block->Start->Prev = Link->Prev;
|
|
|
|
Block->End->Next = Link;
|
|
|
|
Link->Prev = Block->End;
|
|
|
|
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
|
|
|
|
T->Block = Link->Block;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcInsertBlockStartToEnd(PNATIVE_CODE_LINK Start, PNATIVE_CODE_LINK End, PNATIVE_CODE_BLOCK NewBlock)
|
|
|
|
{
|
|
|
|
NewBlock->Start->Prev = Start->Prev;
|
|
|
|
NewBlock->End->Next = End->Next;
|
|
|
|
|
|
|
|
if (Start->Prev)
|
|
|
|
Start->Prev->Next = NewBlock->Start;
|
|
|
|
if (End->Next)
|
|
|
|
End->Next->Prev = NewBlock->End;
|
|
|
|
|
|
|
|
if (Start->Block->Start == Start)
|
|
|
|
Start->Block->Start = NewBlock->Start;
|
|
|
|
|
|
|
|
if (Start->Block->End == End)
|
|
|
|
Start->Block->End = NewBlock->End;
|
|
|
|
|
|
|
|
//Update Block for the current isntructions
|
|
|
|
for (PNATIVE_CODE_LINK T = NewBlock->Start; T && T != NewBlock->End->Next; T = T->Next)
|
|
|
|
T->Block = Start->Block;
|
|
|
|
|
|
|
|
PNATIVE_CODE_LINK EndBlock = End->Next;
|
|
|
|
for (PNATIVE_CODE_LINK T = Start; T && T != EndBlock;)
|
|
|
|
{
|
|
|
|
PNATIVE_CODE_LINK RealNext = T->Next;
|
|
|
|
delete T;
|
|
|
|
T = RealNext;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcCreateLabels(PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
UINT CurrentLabelId = 0;
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T; T = T->Next)
|
|
|
|
{
|
|
|
|
if (!(T->Flags & CODE_FLAG_IS_INST))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
XED_CATEGORY_ENUM Category = XedDecodedInstGetCategory(&T->XedInstruction);
|
|
|
|
if (Category != XED_CATEGORY_COND_BR && Category != XED_CATEGORY_UNCOND_BR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
UINT OperandCount = XedDecodedInstNumOperands(&T->XedInstruction);
|
|
|
|
if (OperandCount < 1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
CONST XED_INST* Inst = XedDecodedInstInst(&T->XedInstruction);
|
|
|
|
if (!Inst)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
CONST XED_OPERAND* Operand = XedInstOperand(Inst, 0);
|
|
|
|
if (!Operand)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
XED_OPERAND_TYPE_ENUM OperandType = XedOperandType(Operand);
|
|
|
|
if (OperandType != XED_OPERAND_TYPE_IMM && OperandType != XED_OPERAND_TYPE_IMM_CONST)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
INT32 BranchDisplacement = XedDecodedInstGetBranchDisplacement(&T->XedInstruction);
|
|
|
|
PNATIVE_CODE_LINK JmpPos = NcValidateJmp(T, BranchDisplacement);
|
|
|
|
if (!JmpPos)
|
|
|
|
{
|
|
|
|
printf("Failed to validate jump. Type: %s, Displacement: %d\n", XedCategoryEnumToString(Category), BranchDisplacement);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (JmpPos->Prev && (JmpPos->Prev->Flags & CODE_FLAG_IS_LABEL))
|
|
|
|
{
|
|
|
|
T->Label = JmpPos->Prev->Label;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NcInsertLinkBefore(JmpPos, new NATIVE_CODE_LINK(CurrentLabelId, Block));
|
|
|
|
Block->LabelIds.push_back(CurrentLabelId);
|
|
|
|
T->Label = CurrentLabelId;
|
|
|
|
++CurrentLabelId;
|
|
|
|
}
|
|
|
|
T->Flags |= CODE_FLAG_IS_REL_JMP;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PNATIVE_CODE_LINK NcValidateJmp(PNATIVE_CODE_LINK Jmp, INT32 Delta)
|
|
|
|
{
|
|
|
|
PNATIVE_CODE_LINK T;
|
|
|
|
if (Delta > 0)
|
|
|
|
{
|
|
|
|
T = Jmp->Next;
|
|
|
|
while (Delta > 0 && T)
|
|
|
|
{
|
|
|
|
if (!(T->Flags & CODE_FLAG_IS_LABEL))
|
|
|
|
Delta -= XedDecodedInstGetLength(&T->XedInstruction);
|
|
|
|
T = T->Next;
|
|
|
|
}
|
|
|
|
if (Delta != 0 || !T)
|
|
|
|
return NULL;
|
|
|
|
while (T && (T->Flags & CODE_FLAG_IS_LABEL))
|
|
|
|
T = T->Next;
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
else if (Delta < 0)
|
|
|
|
{
|
|
|
|
T = Jmp;
|
|
|
|
while (T)
|
|
|
|
{
|
|
|
|
if (!(T->Flags & CODE_FLAG_IS_LABEL))
|
|
|
|
{
|
|
|
|
Delta += XedDecodedInstGetLength(&T->XedInstruction);
|
|
|
|
if (Delta >= 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
T = T->Prev;
|
|
|
|
}
|
|
|
|
if (Delta != 0 || !T)
|
|
|
|
return NULL;
|
|
|
|
while (T && (T->Flags & CODE_FLAG_IS_LABEL))
|
|
|
|
T = T->Next;
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
return Jmp->Next;
|
|
|
|
}
|
|
|
|
|
|
|
|
PNATIVE_CODE_LINK NcDeepCopyLink(PNATIVE_CODE_LINK Link)
|
|
|
|
{
|
|
|
|
if (Link->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
{
|
|
|
|
return new NATIVE_CODE_LINK(Link->Label, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PNATIVE_CODE_LINK NewLink = new NATIVE_CODE_LINK(Link->Flags, Link->RawData, Link->RawDataSize);
|
|
|
|
NewLink->Label = Link->Label;
|
|
|
|
XED_ERROR_ENUM DecodeError = XedDecode(&NewLink->XedInstruction, Link->RawData, Link->RawDataSize);
|
|
|
|
if (DecodeError != XED_ERROR_NONE)
|
|
|
|
{
|
|
|
|
printf("XedDecode failed in NcDeepCopyLink: %s %u\n", XedErrorEnumToString(DecodeError), Link->RawDataSize);
|
|
|
|
delete NewLink;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (Link->Flags & CODE_FLAG_HAS_ASM_OP)
|
|
|
|
{
|
|
|
|
for (STDPAIR<FN_INST_ASM_OP, PVOID> CONST& Op : Link->AsmOperations)
|
|
|
|
{
|
|
|
|
NewLink->AsmOperations.emplace_back(Op.first, Op.second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NewLink;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcDeepCopyPartialBlock(PNATIVE_CODE_LINK Start, PNATIVE_CODE_LINK End, PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
if (!Start || !End || !Start->Block || Start->Block != End->Block || !Block)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
Block->LabelIds.clear();
|
|
|
|
Block->Start = Block->End = NULL;
|
|
|
|
|
|
|
|
for (UINT L : Start->Block->LabelIds)
|
|
|
|
Block->LabelIds.push_back(L);
|
|
|
|
|
|
|
|
for (PNATIVE_CODE_LINK CurLink = Start; CurLink && CurLink != End->Next; CurLink = CurLink->Next)
|
|
|
|
{
|
|
|
|
PNATIVE_CODE_LINK Temp = NcDeepCopyLink(CurLink);
|
|
|
|
if (!Temp)
|
|
|
|
{
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
NcAppendToBlock(Block, Temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcDeepCopyBlock(PNATIVE_CODE_BLOCK Block, PNATIVE_CODE_BLOCK BlockCopy)
|
|
|
|
{
|
|
|
|
return NcDeepCopyPartialBlock(Block->Start, Block->End, BlockCopy);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcPromoteRelJmpTo32(PNATIVE_CODE_LINK Link)
|
|
|
|
{
|
|
|
|
if (XedDecodedInstGetBranchDisplacementWidth(&Link->XedInstruction) == 32)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
XED_ENCODER_INSTRUCTION EncoderInstruction;
|
|
|
|
XED_ENCODER_REQUEST EncoderRequest;
|
|
|
|
UCHAR EncodeBuffer[15];
|
|
|
|
UINT ReturnedSize;
|
|
|
|
XED_ICLASS_ENUM IClass = XedDecodedInstGetIClass(&Link->XedInstruction);
|
|
|
|
|
|
|
|
XedInst1(&EncoderInstruction, XedGlobalMachineState, IClass, 32, XedRelBr(0, 32));
|
|
|
|
XedEncoderRequestZeroSetMode(&EncoderRequest, &XedGlobalMachineState);
|
|
|
|
if (!XedConvertToEncoderRequest(&EncoderRequest, &EncoderInstruction))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
XED_ERROR_ENUM Err = XedEncode(&EncoderRequest, EncodeBuffer, 15, &ReturnedSize);
|
|
|
|
if (XED_ERROR_NONE != Err)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
delete[] Link->RawData;
|
|
|
|
Link->RawDataSize = ReturnedSize;
|
|
|
|
Link->RawData = new UCHAR[ReturnedSize];
|
|
|
|
RtlCopyMemory(Link->RawData, EncodeBuffer, ReturnedSize);
|
|
|
|
|
|
|
|
XedDecodedInstZeroSetMode(&Link->XedInstruction, &XedGlobalMachineState);
|
|
|
|
if (XED_ERROR_NONE != XedDecode(&Link->XedInstruction, Link->RawData, Link->RawDataSize))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcPromoteAllRelJmpTo32(PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_REL_JMP)
|
|
|
|
{
|
|
|
|
if (!NcPromoteRelJmpTo32(T))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcGetDeltaToLabel(PNATIVE_CODE_LINK Link, PINT32 DeltaOut)
|
|
|
|
{
|
|
|
|
INT32 Delta = 0;
|
|
|
|
//First checking backwards because I feel like thats the direction most jmps are in
|
|
|
|
for (PNATIVE_CODE_LINK T = Link; T; T = T->Prev)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
{
|
|
|
|
if (T->Label == Link->Label)
|
|
|
|
{
|
|
|
|
*DeltaOut = Delta;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Delta -= T->RawDataSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Now check forwards
|
|
|
|
Delta = 0;
|
|
|
|
for (PNATIVE_CODE_LINK T = Link->Next; T; T = T->Next)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
{
|
|
|
|
if (T->Label == Link->Label)
|
|
|
|
{
|
|
|
|
*DeltaOut = Delta;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Delta += T->RawDataSize;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcGetDeltaToRandomLabel(PNATIVE_CODE_LINK Link, PINT32 DeltaOut)
|
|
|
|
{
|
|
|
|
std::vector<INT32> Deltas;
|
|
|
|
INT32 Delta = 0;
|
|
|
|
//First checking backwards because I feel like thats the direction most jmps are in
|
|
|
|
for (PNATIVE_CODE_LINK T = Link; T; T = T->Prev)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
{
|
|
|
|
if (T->Label == Link->Label)
|
|
|
|
{
|
|
|
|
Deltas.push_back(Delta);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Delta -= T->RawDataSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Now check forwards
|
|
|
|
Delta = 0;
|
|
|
|
for (PNATIVE_CODE_LINK T = Link->Next; T; T = T->Next)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
{
|
|
|
|
if (T->Label == Link->Label)
|
|
|
|
{
|
|
|
|
Deltas.push_back(Delta);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Delta += T->RawDataSize;
|
|
|
|
}
|
|
|
|
if (Deltas.size() == 0)
|
|
|
|
return FALSE;
|
|
|
|
*DeltaOut = Deltas[RndGetRandomInt(0, Deltas.size() - 1)];
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcFixRelJmps(PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next;)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_REL_JMP)
|
|
|
|
{
|
|
|
|
INT32 BranchDisp = 0;
|
|
|
|
if (!NcGetDeltaToLabel(T, &BranchDisp))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
UINT DispWidth = XedDecodedInstGetBranchDisplacementWidthBits(&T->XedInstruction);
|
|
|
|
if (log2(abs(BranchDisp)) + 1 > DispWidth)
|
|
|
|
{
|
|
|
|
//duh oh
|
|
|
|
if (DispWidth == 32)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
DispWidth = 32;
|
|
|
|
|
|
|
|
//Encode new instruction
|
|
|
|
XED_ENCODER_INSTRUCTION EncoderInstruction;
|
|
|
|
XED_ENCODER_REQUEST EncoderRequest;
|
|
|
|
UCHAR EncodeBuffer[15];
|
|
|
|
UINT ReturnedSize;
|
|
|
|
XED_ICLASS_ENUM IClass = XedDecodedInstGetIClass(&T->XedInstruction);
|
|
|
|
|
|
|
|
//Do the encoding
|
|
|
|
XedInst1(&EncoderInstruction, XedGlobalMachineState, IClass, DispWidth, XedRelBr(0, DispWidth));
|
|
|
|
XedEncoderRequestZeroSetMode(&EncoderRequest, &XedGlobalMachineState);
|
|
|
|
if (!XedConvertToEncoderRequest(&EncoderRequest, &EncoderInstruction))
|
|
|
|
return FALSE;
|
|
|
|
XED_ERROR_ENUM Err = XedEncode(&EncoderRequest, EncodeBuffer, 15, &ReturnedSize);
|
|
|
|
if (XED_ERROR_NONE != Err)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
//fixup T->RawData
|
|
|
|
delete[] T->RawData;
|
|
|
|
T->RawDataSize = ReturnedSize;
|
|
|
|
T->RawData = new UCHAR[ReturnedSize];
|
|
|
|
RtlCopyMemory(T->RawData, EncodeBuffer, ReturnedSize);
|
|
|
|
|
|
|
|
//Decode instruction so its proper and all that
|
|
|
|
XedDecodedInstZeroSetMode(&T->XedInstruction, &XedGlobalMachineState);
|
|
|
|
if (XED_ERROR_NONE != XedDecode(&T->XedInstruction, T->RawData, T->RawDataSize))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
//Go back to the start and loop through all labels again because now this instruction is larger :))))
|
|
|
|
T = Block->Start;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DispWidth = XedDecodedInstGetBranchDisplacementWidth(&T->XedInstruction);
|
|
|
|
switch (DispWidth)
|
|
|
|
{
|
|
|
|
case 1: *(PINT8)&T->RawData[T->RawDataSize - DispWidth] = (INT8)BranchDisp; break;
|
|
|
|
case 2: *(PINT16)&T->RawData[T->RawDataSize - DispWidth] = (INT16)BranchDisp; break;
|
|
|
|
case 4: *(PINT32)&T->RawData[T->RawDataSize - DispWidth] = (INT32)BranchDisp; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
T = T->Next;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcHasIllegalInstructions(PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
//Iterate through and check for rip relative instructions
|
|
|
|
/*for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
UINT OperandCount = XedDecodedInstNumOperands(&T->XedInstruction);
|
|
|
|
if (OperandCount == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL NcDisassemble(PNATIVE_CODE_BLOCK Block, PVOID Buffer, UINT BufferSize)
|
|
|
|
{
|
|
|
|
PUCHAR Buf = (PUCHAR)Buffer;
|
|
|
|
UINT Offset = 0;
|
|
|
|
|
|
|
|
while (Offset < BufferSize)
|
|
|
|
{
|
|
|
|
PNATIVE_CODE_LINK Link = new NATIVE_CODE_LINK;
|
|
|
|
Link->Flags = CODE_FLAG_IS_INST;
|
|
|
|
UINT PossibleSize = min(15, BufferSize - Offset);
|
|
|
|
XED_ERROR_ENUM DecodeError = XedDecode(&Link->XedInstruction, (Buf + Offset), PossibleSize);
|
|
|
|
if (DecodeError != XED_ERROR_NONE)
|
|
|
|
{
|
|
|
|
printf("XedDecode failed with error %s\n", XedErrorEnumToString(DecodeError));
|
|
|
|
NcDeleteBlock(Block);
|
|
|
|
delete Link;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
Link->RawDataSize = XedDecodedInstGetLength(&Link->XedInstruction);
|
|
|
|
Link->RawData = new UCHAR[Link->RawDataSize];
|
|
|
|
RtlCopyMemory(Link->RawData, (Buf + Offset), Link->RawDataSize);
|
|
|
|
|
|
|
|
NcAppendToBlock(Block, Link);
|
|
|
|
|
|
|
|
Offset += Link->RawDataSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
NcCreateLabels(Block);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PVOID NcAssemble(PNATIVE_CODE_BLOCK Block, PUINT OutSize)
|
|
|
|
{
|
|
|
|
if (!NcFixRelJmps(Block))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
*OutSize = NcCalcBlockSizeInBytes(Block);
|
|
|
|
|
|
|
|
PUCHAR Buffer = new UCHAR[*OutSize]; // (PUCHAR)malloc(*OutSize);
|
|
|
|
if (!Buffer)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
PUCHAR BufferOffset = Buffer;
|
|
|
|
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
continue;
|
|
|
|
RtlCopyMemory(BufferOffset, T->RawData, T->RawDataSize);
|
|
|
|
if (T->Flags & CODE_FLAG_HAS_ASM_OP)
|
|
|
|
{
|
|
|
|
for (STDPAIR<FN_INST_ASM_OP, PVOID> CONST& Op : T->AsmOperations)
|
|
|
|
Op.first(T, BufferOffset, Op.second);
|
|
|
|
}
|
|
|
|
BufferOffset += T->RawDataSize;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return Buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
//assumes all jmps already promoted to 32 bit branch displacement size
|
|
|
|
PVOID NcAssembleEx(PNATIVE_CODE_BLOCK Block, PUINT OutSize)
|
|
|
|
{
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next;)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_REL_JMP)
|
|
|
|
{
|
|
|
|
INT32 BranchDisp = 0;
|
|
|
|
if (!NcGetDeltaToRandomLabel(T, &BranchDisp))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
UINT DispWidth = XedDecodedInstGetBranchDisplacementWidth(&T->XedInstruction);
|
|
|
|
switch (DispWidth)
|
|
|
|
{
|
|
|
|
case 1: *(PINT8)&T->RawData[T->RawDataSize - DispWidth] = (INT8)BranchDisp; break;
|
|
|
|
case 2: *(PINT16)&T->RawData[T->RawDataSize - DispWidth] = (INT16)BranchDisp; break;
|
|
|
|
case 4: *(PINT32)&T->RawData[T->RawDataSize - DispWidth] = (INT32)BranchDisp; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
T = T->Next;
|
|
|
|
}
|
|
|
|
|
|
|
|
*OutSize = NcCalcBlockSizeInBytes(Block);
|
|
|
|
|
|
|
|
PUCHAR Buffer = new UCHAR[*OutSize];
|
|
|
|
if (!Buffer)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
PUCHAR BufferOffset = Buffer;
|
|
|
|
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
continue;
|
|
|
|
RtlCopyMemory(BufferOffset, T->RawData, T->RawDataSize);
|
|
|
|
if (T->Flags & CODE_FLAG_HAS_ASM_OP)
|
|
|
|
{
|
|
|
|
for (STDPAIR<FN_INST_ASM_OP, PVOID> CONST& Op : T->AsmOperations)
|
|
|
|
Op.first(T, BufferOffset, Op.second);
|
|
|
|
}
|
|
|
|
BufferOffset += T->RawDataSize;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return Buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID NcDeleteBlock(PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
if (!Block->Start || !Block->End)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PNATIVE_CODE_LINK BlockEnding = Block->End->Next;
|
|
|
|
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != BlockEnding;)
|
|
|
|
{
|
|
|
|
PNATIVE_CODE_LINK Next = T->Next;
|
|
|
|
delete T;
|
|
|
|
T = Next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID NcDebugPrint(PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
HANDLE ConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
if (!ConsoleHandle)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
|
|
|
|
{
|
|
|
|
if (T->Flags & CODE_FLAG_IS_LABEL)
|
|
|
|
{
|
|
|
|
SetConsoleTextAttribute(ConsoleHandle, FOREGROUND_GREEN | FOREGROUND_RED);
|
|
|
|
printf("Label: %u\n", T->Label);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
XED_ICLASS_ENUM IClass = XedDecodedInstGetIClass(&T->XedInstruction);
|
|
|
|
if (T->Flags & CODE_FLAG_IS_REL_JMP)
|
|
|
|
{
|
|
|
|
SetConsoleTextAttribute(ConsoleHandle, FOREGROUND_GREEN | FOREGROUND_RED);
|
|
|
|
printf("%s: %u\n", XedIClassEnumToString(IClass), T->Label);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetConsoleTextAttribute(ConsoleHandle, FOREGROUND_GREEN | FOREGROUND_BLUE);
|
|
|
|
printf("%s\n", XedIClassEnumToString(IClass));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID NcPrintBlockCode(PNATIVE_CODE_BLOCK Block)
|
|
|
|
{
|
|
|
|
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
|
|
|
|
{
|
|
|
|
if (!(T->Flags & CODE_FLAG_IS_LABEL))
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < T->RawDataSize; i++)
|
|
|
|
{
|
|
|
|
std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)T->RawData[i] << ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|