int get_instructions_size(void* code, int size) { _DecodedInst decodedInstructions[32]; _OffsetType offset = 0; unsigned int decodedInstructionsCount; #ifdef __x86_64__ _DecodeType dt = Decode64Bits; #elif __i386__ _DecodeType dt = Decode32Bits; #else #error "unknown architecture" #endif distorm_decode(offset, code, size, dt, decodedInstructions, 32, &decodedInstructionsCount); int i; int totalsize = 0; int minsize = get_jmp_size(); for (i = 0; i < decodedInstructionsCount; i++) { totalsize = totalsize + decodedInstructions[i].size; if (totalsize >= minsize) { return totalsize; } } return totalsize; }
// Count instructions BYTE* instructionCount(BYTE *func, int tcount) { #ifndef _WIN64 _DecodeType dt = Decode32Bits; #else _DecodeType dt = Decode64Bits; #endif #define MAX_INSTRUCTIONS 100 _DecodeResult res; _DecodedInst di[MAX_INSTRUCTIONS]; unsigned int dic = 0; res = distorm_decode(0, (const BYTE *) func, 15, dt, di, MAX_INSTRUCTIONS, &dic); if(res == DECRES_INPUTERR) dbg("ERROR: distorm_decode failed!"); DWORD is = 0; for(DWORD i=0;i<dic;i++) { if(is >= tcount) return func+is; is += di[i].size; } return 0; }
char* __cdecl GetDisasm(ULONG_PTR pAddress, int* retLen = NULL){ //just a helper doesnt set error code.. _DecodeResult res; _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; unsigned int decodedInstructionsCount = 0; _DecodeType dt = isX64 ? Decode64Bits : Decode32Bits; _OffsetType offset = 0; res = distorm_decode(offset, // offset for buffer (const BYTE *) pAddress, // buffer to disassemble 50, // function size (code size to disasm) dt, // x86 or x64? decodedInstructions, // decoded instr MAX_INSTRUCTIONS, // array size &decodedInstructionsCount // how many instr were disassembled? ); if (res == DECRES_INPUTERR) return NULL; int bufsz = 120; char* tmp = (char*)malloc(bufsz); memset(tmp, 0, bufsz); _snprintf(tmp, bufsz-1 , "%10x %-10s %-6s %s\n", pAddress, decodedInstructions[0].instructionHex.p, decodedInstructions[0].mnemonic.p, decodedInstructions[0].operands.p ); if(retLen !=NULL) *retLen = decodedInstructions[0].size; return tmp; }
int HookableBytes(ULONG_PTR Function){ _DecodeResult res; _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; unsigned int decodedInstructionsCount = 0; _DecodeType dt = isX64 ? Decode64Bits : Decode32Bits; _OffsetType offset = 0; res = distorm_decode(offset, // offset for buffer (const BYTE *) Function, // buffer to disassemble 50, // function size (code size to disasm) // 50 instr should be _quite_ enough dt, // x86 or x64? decodedInstructions, // decoded instr MAX_INSTRUCTIONS, // array size &decodedInstructionsCount // how many instr were disassembled? ); if (res == DECRES_INPUTERR) return 0; DWORD InstrSize = 0; for (UINT x = 0; x < decodedInstructionsCount; x++) { BYTE *pCurInstr = (BYTE *) (InstrSize + (ULONG_PTR)Function); if (InstrSize >= 15) break; if(UnSupportedOpcode(pCurInstr, g_NumberOfHooks)) break; InstrSize += decodedInstructions[x].size; } return InstrSize; }
STATUS ShuDisassembleShellcode( IN PVOID DumpedShellcode, IN PVOID ShellcodeAddress, IN DWORD dwSize ) { _DecodeResult DecRes; _DecodedInst *DecodedInstructions; _DecodeType dt = Decode32Bits; _OffsetType offset; DWORD dwDecodedInstructionsCount; DWORD dwNext; DWORD i; CHAR szLogPath[MAX_PATH]; CHAR szShellcodeDisassFile[MAX_PATH]; ERRORINFO err; FILE *ShellcodeFile; offset = 0; dwDecodedInstructionsCount = 0; DecodedInstructions = (_DecodedInst *)LocalAlloc(LMEM_ZEROINIT, MAX_INSTRUCTIONS * sizeof(_DecodedInst)); sprintf(szShellcodeDisassFile, "\\ShellcodeDisass.txt"); strncpy( szLogPath, MCEDP_REGCONFIG.LOG_PATH, MAX_PATH); strncat(szLogPath, szShellcodeDisassFile, MAX_PATH); ShellcodeFile = fopen( szLogPath, "a"); if ( ShellcodeFile == NULL ) { REPORT_ERROR("fopen()", &err); LocalFree(DecodedInstructions); return MCEDP_STATUS_INTERNAL_ERROR; } while ( TRUE ) { DecRes = distorm_decode(offset, (const unsigned char*)DumpedShellcode, dwSize, dt, DecodedInstructions, MAX_INSTRUCTIONS, (unsigned int *)&dwDecodedInstructionsCount); if (DecRes == DECRES_INPUTERR) return MCEDP_STATUS_GENERAL_FAIL; for ( i = 0; i < dwDecodedInstructionsCount; i++ ) fprintf(ShellcodeFile, "%0*I64x (%02d) %-24s %s%s%s\n", dt != Decode64Bits ? 8 : 16, DecodedInstructions[i].offset + (DWORD)ShellcodeAddress, DecodedInstructions[i].size, (char*)DecodedInstructions[i].instructionHex.p, (char*)DecodedInstructions[i].mnemonic.p, DecodedInstructions[i].operands.length != 0 ? " " : "", (char*)DecodedInstructions[i].operands.p); if ( DecRes == DECRES_SUCCESS || dwDecodedInstructionsCount == 0 ) break; dwNext = (unsigned long)(DecodedInstructions[dwDecodedInstructionsCount-1].offset - offset); dwNext += DecodedInstructions[dwDecodedInstructionsCount-1].size; DumpedShellcode = (PVOID)((unsigned int)DumpedShellcode + dwNext); dwSize -= dwNext; offset += dwNext; } LocalFree(DecodedInstructions); fclose(ShellcodeFile); return MCEDP_STATUS_SUCCESS; }
void x86dump(const uint8_t *addr, const char *msg) { report("[x] Disassembling 0x%x: %z", addr, msg); while (1) { unsigned int used_instruction_count = 0; _DecodedInst ins; int ret = distorm_decode((uintptr_t) addr, addr, 16, Decode32Bits, &ins, 1, &used_instruction_count); if((ret != DECRES_SUCCESS && ret != DECRES_MEMORYERR) || used_instruction_count != 1) { report("[-] Disassembly failed"); return; } char extra[256]; extra[0] = 0; if(*addr == 0xe8) { const uint8_t *fn = addr + *(const uint32_t *)(addr + 1) + 5; sprintf(extra, "; 0x%p %s", fn, symbol(fn)); } else if(*addr == 0xff && addr[1] == 0x25) { const uint8_t *fn = **(const uint8_t ***)(addr + 2); sprintf(extra, "; 0x%p %s", fn, symbol(fn)); } // b879e0817c MOV EAX, 0x7c81e079 // ffd0 CALL EAX else if(*addr == 0xb8 && addr[5] == 0xff && addr[6] == 0xd0) { const uint8_t *fn = *(const uint8_t **)(addr + 1); sprintf(extra, "; 0x%p %s", fn, symbol(fn)); } char hex[33]; sprintf(hex, "%-12s", ins.instructionHex.p); if(extra[0] != 0) { report("0x%x %z %z %z %z", addr, hex, ins.mnemonic.p, ins.operands.p, extra); } else { report("0x%x %z %z %z", addr, hex, ins.mnemonic.p, ins.operands.p); } switch (*addr) { case 0xc2: case 0xc3: return; case 0xff: switch (addr[1]) { case 0x25: case 0xe0: case 0xe1: return; } } addr += ins.size; } }
STATUS ShuDisassmbleRopInstructions( IN PVOID Address, OUT PCHAR szInstruction, IN DWORD dwSize ) { _DecodeResult DecRes; _DecodedInst *DecodedInstructions; _DecodeType dt = Decode32Bits; _OffsetType offset; CHAR szDecodedInst[1024]; DWORD dwDecodedInstructionsCount; DWORD dwNext; DWORD i; offset = 0; dwDecodedInstructionsCount = 0; DecodedInstructions = (_DecodedInst *)LocalAlloc(LMEM_ZEROINIT, MAX_INSTRUCTIONS * sizeof(_DecodedInst)); while ( TRUE ) { DecRes = distorm_decode(offset, (const unsigned char*)Address, dwSize, dt, DecodedInstructions, MAX_INSTRUCTIONS, (unsigned int *)&dwDecodedInstructionsCount); if (DecRes == DECRES_INPUTERR) return MCEDP_STATUS_GENERAL_FAIL; for ( i = 0; i < dwDecodedInstructionsCount; i++ ) { SecureZeroMemory(szDecodedInst, 1024); sprintf(szDecodedInst, "%0*I64x (%02d) %-24s %s%s%s\n", dt != Decode64Bits ? 8 : 16, DecodedInstructions[i].offset + (DWORD)Address, DecodedInstructions[i].size, (char*)DecodedInstructions[i].instructionHex.p, (char*)DecodedInstructions[i].mnemonic.p, DecodedInstructions[i].operands.length != 0 ? " " : "", (char*)DecodedInstructions[i].operands.p); strcat( szInstruction , szDecodedInst); /* Using Decompose API with DF_STOP_ON_RET ? */ if ( strstr((char*)DecodedInstructions[i].mnemonic.p, "RET") != NULL || strstr((char*)DecodedInstructions[i].operands.p, "RET") != NULL ) { LocalFree(DecodedInstructions); return MCEDP_STATUS_SUCCESS; } } if ( DecRes == DECRES_SUCCESS || dwDecodedInstructionsCount == 0 ) break; dwNext = (unsigned long)(DecodedInstructions[dwDecodedInstructionsCount-1].offset - offset); dwNext += DecodedInstructions[dwDecodedInstructionsCount-1].size; Address = (PVOID)((unsigned int)Address + dwNext); dwSize -= dwNext; offset += dwNext; } LocalFree(DecodedInstructions); return MCEDP_STATUS_SUCCESS; }
int NCodeHook<ArchT>::getMinOffset(const unsigned char* codePtr, unsigned int jumpPatchSize) { _DecodeResult result; _DecodedInst instructions[MaxInstructions]; unsigned int instructionCount = 0; result = distorm_decode(0, codePtr, 20, ArchT::DisasmType, instructions, MaxInstructions, &instructionCount); if (result != DECRES_SUCCESS) return -1; unsigned int offset = 0; for (unsigned int i = 0; offset < jumpPatchSize && i < instructionCount; ++i) { if (isBranch((const char*)instructions[i].mnemonic.p)) return -1; offset += instructions[i].size; } // If we were unable to disassemble enough instructions we fail. if (offset < jumpPatchSize) return -1; return offset; }
bool ProcessAccessHelp::disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset) { // Holds the result of the decoding. _DecodeResult res; // next is used for instruction's offset synchronization. // decodedInstructionsCount holds the count of filled instructions' array by the decoder. decodedInstructionsCount = 0; _OffsetType offset = startOffset; res = distorm_decode(offset, dataBuffer, (int)bufferSize, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount); /* for (unsigned int i = 0; i < decodedInstructionsCount; i++) { #ifdef SUPPORT_64BIT_OFFSET printf("%0*I64x (%02d) %-24s %s%s%s\n", dt != Decode64Bits ? 8 : 16, decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p); #else printf("%08x (%02d) %-24s %s%s%s\n", decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p); #endif }*/ if (res == DECRES_INPUTERR) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"disassembleMemory :: res == DECRES_INPUTERR"); #endif return false; } else if (res == DECRES_SUCCESS) { //printf("disassembleMemory :: res == DECRES_SUCCESS\n"); return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"disassembleMemory :: res == %d", res); #endif return true; //not all instructions fit in buffer } }
ULONG CalcReplaceSize (ULONG_PTR pOrigFunction) { #define MAX_INSTRUCTIONS 15 _DecodeResult res; ULONG ReplaceSize = 0; ULONG Index = 0; _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; unsigned int decodedInstructionsCount = 0; #ifndef _WIN64 _DecodeType dt = Decode32Bits; #else _DecodeType dt = Decode64Bits; #endif _OffsetType offset = 0; res = distorm_decode(offset, (const BYTE *) pOrigFunction, 45, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount ); if (res == DECRES_INPUTERR) return 0; for (Index; Index < decodedInstructionsCount; Index++) { if (ReplaceSize >= JMP_MIN_LENGTH) break; ReplaceSize += decodedInstructions[Index].size; } return ReplaceSize; }
VOID *CreateBridge(HOOK_INFO *hinfo) { if (g_pBridgeBuffer == NULL) return NULL; UINT x = 0; _DecodeResult res; _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; unsigned int decodedInstructionsCount = 0; _DecodeType dt = isX64 ? Decode64Bits : Decode32Bits; _OffsetType offset = 0; ULONG_PTR Function = hinfo->Function; int JumpSize = GetJumpSize(hinfo->hooktype); res = distorm_decode(offset, // offset for buffer (const BYTE *) Function, // buffer to disassemble 50, // function size (code size to disasm) // 50 instr should be _quite_ enough dt, // x86 or x64? decodedInstructions, // decoded instr MAX_INSTRUCTIONS, // array size &decodedInstructionsCount // how many instr were disassembled? ); if (res == DECRES_INPUTERR){ sprintf(lastError, "Could not disassemble address %x", (UINT)Function); //dbgmsg(lastError); lastErrorCode = he_cantDisasm; return NULL; } DWORD InstrSize = 0; VOID *pBridge = (VOID *) &g_pBridgeBuffer[g_CurrentBridgeBufferSize]; //copy full instructions from API to our trampoline. for (x ; x < decodedInstructionsCount; x++) { if (InstrSize >= JumpSize) break; BYTE *pCurInstr = (BYTE *) (InstrSize + (ULONG_PTR) Function); if(logLevel >=3){ dbgmsg(3, "%s+%d \t %-10s %-6s %s", hinfo->ApiName, InstrSize, decodedInstructions[x].instructionHex.p, decodedInstructions[x].mnemonic.p, decodedInstructions[x].operands.p ); } if( UnSupportedOpcode(pCurInstr, hinfo->index) ){ dbgmsg(0, "CreatreBridge::UnSupportedOpcode found missed in pre-Validation?! needed=%d, hookable=%d, cur=%d, type=%s", JumpSize, hinfo->hookableBytes,InstrSize, GetHookName(hinfo->hooktype) ); DebugBreak(); //if we leave here, g_CurrentBridgeBufferSize has been incremented and bytes copied to //the alloced g_pBridgeBuffer, but the API itself is untouched. return NULL; } memcpy(&g_pBridgeBuffer[g_CurrentBridgeBufferSize], (VOID *) pCurInstr, decodedInstructions[x].size); g_CurrentBridgeBufferSize += decodedInstructions[x].size; InstrSize += decodedInstructions[x].size; } hinfo->OverwrittenInstructions = x; hinfo->OverwrittenBytes = InstrSize; //we will 0xCC this many in API latter for debugging sake... //to leave trampoline... hookType ht = isX64 ? ht_jmp : ht_pushret; //both absolute address jumps for safety... bool rv = WriteJump(&g_pBridgeBuffer[g_CurrentBridgeBufferSize], Function + InstrSize, ht, hinfo->index); g_CurrentBridgeBufferSize += GetJumpSize(ht); if(!rv) return NULL; return pBridge; }
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { UNICODE_STRING pFcnName; // Holds the result of the decoding. _DecodeResult res; // Decoded instruction information. _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; // next is used for instruction's offset synchronization. // decodedInstructionsCount holds the count of filled instructions' array by the decoder. unsigned int decodedInstructionsCount = 0, i, next; // Default decoding mode is 32 bits, could be set by command line. _DecodeType dt = Decode32Bits; // Default offset for buffer is 0, could be set in command line. _OffsetType offset = 0; char* errch = NULL; // Buffer to disassemble. unsigned char *buf; int len = 100; // Register unload routine DriverObject->DriverUnload = DriverUnload; DbgPrint("diStorm Loaded!\n"); // Get address of KeBugCheck RtlInitUnicodeString(&pFcnName, L"KeBugCheck"); buf = (char *)MmGetSystemRoutineAddress(&pFcnName); offset = (unsigned) (_OffsetType)buf; DbgPrint("Resolving KeBugCheck @ 0x%08x\n", buf); // Decode the buffer at given offset (virtual address). while (1) { res = distorm_decode(offset, (const unsigned char*)buf, len, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount); if (res == DECRES_INPUTERR) { DbgPrint(("NULL Buffer?!\n")); break; } for (i = 0; i < decodedInstructionsCount; i++) { // Note that we print the offset as a 64 bits variable!!! // It might be that you'll have to change it to %08X... DbgPrint("%08I64x (%02d) %s %s %s\n", decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, (char*)decodedInstructions[i].operands.p); } if (res == DECRES_SUCCESS || decodedInstructionsCount == 0) { break; // All instructions were decoded. } // Synchronize: next = (unsigned int)(decodedInstructions[decodedInstructionsCount-1].offset - offset); next += decodedInstructions[decodedInstructionsCount-1].size; // Advance ptr and recalc offset. buf += next; len -= next; offset += next; } DbgPrint(("Done!\n")); return STATUS_SUCCESS; }
void Permutator::ProcessNode(Node* n, std::ofstream& gvFile) { _DecodeResult res; unsigned int decodedInstructionsCount = 0; _DecodeType dt = Decode32Bits; _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; std::string stateStyleStart = "[ style = \"filled\" penwidth = 1 fillcolor = \"white\" fontname = \"Courier New\" " "shape = \"Mrecord\" label =<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">\""; std::string stateStyleEnd = "</table>> ];\n"; std::string stateHeaderStart = "<tr><td bgcolor=\"black\" align=\"center\" colspan=\"2\"><font color=\"white\">"; std::string stateHeaderEnd = "</font></td></tr>"; std::string stateDataStart = "<tr><td align=\"left\">"; std::string stateDataEnd = "</td></tr>"; BYTE* instructions = n->GetInstructions(); std::stringstream stream; stream << std::hex << n->GetOffset(); std::string stateName = "\"0x" + stream.str() + "\""; try { gvFile.write(stateName.c_str(), stateName.length()); gvFile.write(stateStyleStart.c_str(), stateStyleStart.length()); gvFile.write(stateHeaderStart.c_str(), stateHeaderStart.length()); gvFile.write(stateName.c_str(), stateName.length()); gvFile.write(stateHeaderEnd.c_str(), stateHeaderEnd.length()); while (1) { res = distorm_decode(n->GetOffset(), (const unsigned char*)instructions, n->GetSize(), dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount); if (res == DECRES_INPUTERR) { std::cerr << "ProcessNode: Disassembly error" << std::endl; return; } for (unsigned int i = 0; i < decodedInstructionsCount; ++i) { gvFile.write(stateDataStart.c_str(), stateDataStart.length()); gvFile.write((char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].mnemonic.length); if (decodedInstructions[i].operands.length != 0) { gvFile.write(" ", 1); gvFile.write((char*)decodedInstructions[i].operands.p, decodedInstructions[i].operands.length); } gvFile.write(stateDataEnd.c_str(), stateDataEnd.length()); } if (res == DECRES_SUCCESS) break; } gvFile.write(stateStyleEnd.c_str(), stateStyleEnd.length()); for (unsigned int i = 0; i < n->GetChildren().size(); ++i) { ProcessNode(n->GetChildren().at(i), gvFile); } } catch (std::fstream::failure e) { std::cerr << "ProcessNode: Error while writing node information to graphviz file: " << e.what() << std::endl; return; } return; }
void Permutator::__CreateGraph(BYTE* sectionData, _OffsetType blockOffset, DWORD dwSectionSize, _OffsetType parentOffset) { _DecodeResult res; unsigned int decodedInstructionsCount = 0; _DecodeType dt = Decode32Bits; _OffsetType offsetEnd; _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; unsigned int i; QWORD tmpOffset = blockOffset; std::string mnemonic, operand; std::vector<Block> targets; std::queue<Block> blockQueue; bool skipFlag; bool disasmStopFlag; Block block; block.offset = blockOffset; block.parentOffset = parentOffset; blockQueue.push(block); while (!blockQueue.empty()) { skipFlag = false; Block currentBlock = blockQueue.front(); blockQueue.pop(); for (std::vector<Block>::iterator it = targets.begin(); it != targets.end(); ++it) { if (((*it).offset == currentBlock.offset) && (*it).parentOffset == currentBlock.parentOffset) { skipFlag = true; break; } } if (skipFlag) continue; // Disassembly part while (1) { disasmStopFlag = false; res = distorm_decode(currentBlock.offset, (const unsigned char*)(sectionData + currentBlock.offset), (DWORD)(dwSectionSize - currentBlock.offset), dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount); if (res == DECRES_INPUTERR) { free(sectionData); return; } for (i = 0; i < decodedInstructionsCount; ++i) { mnemonic = (reinterpret_cast<char*>(decodedInstructions[i].mnemonic.p)); if (IsJump(mnemonic) || mnemonic.compare("RET") == 0 || mnemonic.compare("RETN") == 0 || mnemonic.substr(0, 2).compare("DB") == 0) { disasmStopFlag = true; break; } if (mnemonic.compare("CALL") == 0) { std::string functionOperand = reinterpret_cast<char*> (decodedInstructions[i].operands.p); if (IsRegister(functionOperand) || !IsFunctionOperandValid(functionOperand)) continue; QWORD functionOffset = std::stoll(functionOperand, nullptr, 0); graph.AddFunctionOffset(tmpOffset, functionOffset - tmpOffset); } tmpOffset += decodedInstructions[i].size; } if (disasmStopFlag) break; } offsetEnd = decodedInstructions[i].offset; DWORD blockSize = (DWORD)(offsetEnd + decodedInstructions[i].size - currentBlock.offset); currentBlock.blockSize = blockSize; // Set 1 to block places in dataBytes for (DWORD j = 0; j < blockSize; ++j) { dataBytes[currentBlock.offset + j] = 1; } targets.push_back(currentBlock); if (mnemonic.compare("RET") == 0 || mnemonic.compare("RETN") == 0 || mnemonic.substr(0, 2).compare("DB") == 0) continue; operand = reinterpret_cast<char*>(decodedInstructions[i].operands.p); operand.resize(decodedInstructions[i].operands.length); if (IsRegister(operand)) continue; QWORD newOffset = std::stoll(operand, nullptr, 0); if (!CheckRange(newOffset)) { std::cerr << "Offset out of CODE section!" << std::endl; continue; } Block positiveJumpBlock; positiveJumpBlock.offset = newOffset; positiveJumpBlock.parentOffset = currentBlock.offset; blockQueue.push(positiveJumpBlock); if (mnemonic.compare("JMP") == 0) continue; QWORD jumpFalseOffset = offsetEnd + decodedInstructions[i].size; if (!CheckRange(newOffset)) { std::cerr << "Offset out of CODE section!" << std::endl; continue; } Block negativeJumpBlock; negativeJumpBlock.offset = jumpFalseOffset; negativeJumpBlock.parentOffset = currentBlock.offset; blockQueue.push(negativeJumpBlock); } // Graph creation for (DWORD i = 0; i < targets.size(); ++i) { Block b = targets.at(i); Node* n = new Node(); n->SetOffset((DWORD) b.offset); n->SetInstructions((BYTE*)(sectionData + b.offset), b.blockSize); graph.AddNode(n, (DWORD)b.parentOffset); } return; }
void Permutator::_CreateGraph(BYTE* sectionData, _OffsetType blockOffset, DWORD dwSectionSize, _OffsetType parentOffset, std::vector<Block>& targets) { _DecodeResult res; unsigned int decodedInstructionsCount = 0; _DecodeType dt = Decode32Bits; _OffsetType offset = blockOffset; _OffsetType offsetEnd; _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; unsigned int i; QWORD tmpOffset = blockOffset; std::string mnemonic, operand; bool skipFlag; while (1) { res = distorm_decode(offset, (const unsigned char*)sectionData, dwSectionSize, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount); if (res == DECRES_INPUTERR) { free(sectionData); return; } for (i = 0; i < decodedInstructionsCount; ++i) { mnemonic = (reinterpret_cast<char*>(decodedInstructions[i].mnemonic.p)); if (IsJump(mnemonic) || mnemonic.compare("RET") == 0 || mnemonic.compare("RETN") == 0 || mnemonic.substr(0, 2).compare("DB") == 0) { break; } if (mnemonic.compare("CALL") == 0) { std::string functionOperand = reinterpret_cast<char*> (decodedInstructions[i].operands.p); if (IsRegister(functionOperand) || !IsFunctionOperandValid(functionOperand)) continue; QWORD functionOffset = std::stoll(functionOperand, nullptr, 0); graph.AddFunctionOffset(tmpOffset, functionOffset - tmpOffset); } tmpOffset += decodedInstructions[i].size; } // Main part of graph creation offsetEnd = decodedInstructions[i].offset; DWORD blockSize = (DWORD)(offsetEnd + decodedInstructions[i].size - offset); Node* node = new Node(); // Set 1 to block places in dataBytes for (DWORD j = 0; j < blockSize; ++j) { dataBytes[blockOffset + j] = 1; } node->SetOffset((DWORD)offset); node->SetInstructions(sectionData, blockSize); // Newly added code skipFlag = false; for (std::vector<Block>::iterator it = targets.begin(); it != targets.end(); ++it) { if (((*it).offset == node->GetOffset()) && (*it).parentOffset == parentOffset) { skipFlag = true; break; } } if (skipFlag) return; Block b; b.offset = node->GetOffset(); b.parentOffset = parentOffset; targets.push_back(b); if (graph.AddNode(node, (DWORD)parentOffset)) { return; } if (mnemonic.compare("RET") == 0 || mnemonic.compare("RETN") == 0 || mnemonic.substr(0, 2).compare("DB") == 0) return; operand = reinterpret_cast<char*>(decodedInstructions[i].operands.p); operand.resize(decodedInstructions[i].operands.length); if (IsRegister(operand)) return; QWORD newOffset = std::stoll(operand, nullptr, 0); if (!CheckRange(newOffset)) { std::cerr << "Offset out of CODE section!" << std::endl; return; } _CreateGraph(sectionData + blockSize + (newOffset - offsetEnd - decodedInstructions[i].size), newOffset, dwSectionSize - (DWORD)newOffset + (DWORD)offset, node->GetOffset(), targets); if (mnemonic.compare("JMP") == 0) return; QWORD jumpFalseOffset = offsetEnd + decodedInstructions[i].size; _CreateGraph(sectionData + jumpFalseOffset - offset, jumpFalseOffset, dwSectionSize - (DWORD)jumpFalseOffset + (DWORD)offset, node->GetOffset(), targets); break; } }