Files
2023-02-19 20:54:19 +01:00

227 lines
4.9 KiB
C++

#include "PeDisasm.h"
#include <QtCore>
using namespace pe_bear;
PeDisasm::PeDisasm(PEFile *pe, size_t _previewSize)
: __disasm_super(),
m_PE(pe), previewSize(_previewSize),
firstOffset(0), isInit(false), isBitModeAuto(true)
{
if (pe == NULL) throw CustomException("PE not initialized!");
}
bool PeDisasm::init(const offset_t offset, Executable::exe_bits bitMode)
{
this->isInit = false;
clearTable();
if (!m_PE) {
return false;
}
this->firstOffset = offset;
if (bitMode == Executable::UNKNOWN) {
this->isBitModeAuto = true;
this->m_bitMode = m_PE->getBitMode();
} else {
this->m_bitMode = bitMode;
}
if (m_PE->getContentSize() < offset) {
return false;
}
size_t maxSize = m_PE->getContentSize() - offset;
size_t disasmSize = (maxSize > previewSize) ? previewSize : maxSize;
uint8_t *buf = m_PE->getContentAt(offset, disasmSize);
if (!buf) {
return false;
}
const bool isOk = __disasm_super::init(buf, maxSize, disasmSize, offset, m_bitMode);
this->isInit = isOk;
return isOk;
}
bool PeDisasm::fillTable()
{
clearTable();
if (!this->isInit) {
return false;
}
bool isOk = __disasm_super::fillTable();
if (isOk) {
isOk = fillOffsetTable();
}
return isOk;
}
bool PeDisasm::fillOffsetTable() {
this->offsetTable.clear();
size_t count = this->m_table.size();
if (count == 0) return false;
for (size_t i = 0; i < count; i++) {
offset_t offset = getRawAt(i);
if (offset == INVALID_ADDR) {
this->offsetTable.push_back(INVALID_ADDR);
continue;
}
try {
offset_t rva = m_PE->rawToRva(offset);
this->offsetTable.push_back(rva);
} catch (CustomException e) {
this->offsetTable.push_back(INVALID_ADDR);
}
}
return true;
}
bool PeDisasm::isRvaContnuous(int index) const
{
if (index == 0) return true;
if ((size_t)index >= m_table.size()) return true;
offset_t prevRva = this->getRvaAt(index-1);
size_t chunkSize = getChunkSize(index-1);
offset_t calcRva = prevRva + chunkSize;
offset_t currRva = this->getRvaAt(index);
if (currRva != calcRva) {
return false;
}
return true;
}
offset_t PeDisasm::getRawAt(int index) const
{
const offset_t instrOffset = __disasm_super::getRawAt(index);
if (instrOffset == INVALID_ADDR) {
return INVALID_ADDR;
}
offset_t offset = firstOffset + instrOffset;
return offset;
}
offset_t PeDisasm::getRvaAt(int index) const
{
if ((size_t)index >= this->offsetTable.size()) return INVALID_ADDR;
return this->offsetTable[index];
}
int32_t PeDisasm::getTargetDelta(int index) const
{
if (!m_PE) return 0;
bool isOk = false;
offset_t rva = getTargetRVA(index, isOk);
if (!isOk) return 0;
offset_t currRVA = getRvaAt(index);
return (int32_t)(rva - currRVA);
}
offset_t PeDisasm::getArgRVA(int index, int argNum, bool &isOk) const
{
offset_t targetVA = PeDisasm::getArgVA(index, argNum, isOk);
if (!isOk) {
return INVALID_ADDR;
}
// only if the target address belongs to the current executable, convert it to RVA:
if (m_PE->isValidVA(targetVA)) {
return m_PE->VaToRva(targetVA);
}
return INVALID_ADDR;
}
offset_t PeDisasm::getTargetVA(int index, bool &isOk) const
{
offset_t targetAddr = INVALID_ADDR;
for (int i = 0; i <= MAX_ARG_NUM; i++ ) {
targetAddr = getArgVA(index, i, isOk);
if (targetAddr != INVALID_ADDR) break;
}
return targetAddr;
}
offset_t PeDisasm::getTargetRVA(int index, bool &isOk) const
{
offset_t targetAddr = getTargetVA(index, isOk);
if (!isOk || !m_PE) {
return INVALID_ADDR;
}
// only if the target address belongs to the current executable, convert it to RVA:
if (!m_PE->isValidVA(targetAddr)) {
return INVALID_ADDR;
}
return m_PE->VaToRva(targetAddr);
}
offset_t PeDisasm::getTargetRaw(int index, bool &isOk) const
{
isOk = false;
if (!m_PE) return INVALID_ADDR;
bool ok = false;
offset_t rva = getTargetRVA(index, ok);
if (!ok) return INVALID_ADDR; //failed to get RVA
offset_t raw = m_PE->toRaw(rva, Executable::RVA);
if (raw != INVALID_ADDR) {
isOk = true;
}
return raw;
}
QString PeDisasm::getStringAt(offset_t rva) const
{
if (!m_PE) return "";
offset_t raw_target = INVALID_ADDR;
bool isValid = true;
try {
raw_target = m_PE->rvaToRaw(rva);
} catch (CustomException e) {
isValid = false;
}
if (!isValid) return "";
QString str = m_PE->getStringValue(raw_target, 150);
if (str.size() == 1) {
str = m_PE->getWAsciiStringValue(raw_target, 150);
if (str.trimmed().length() > 1) {
return "L\'" + str + "\'";
}
}
if (str.trimmed().length() == 0) return "";
return "\'" + str + "\'";
}
bool PeDisasm::isCallToRet(int index) const
{
using namespace minidis;
if (!m_PE) return false;
const mnem_type mnem = this->getMnemType(index);
if (mnem != MT_CALL) return false;
//is pointer to RET?
static const BYTE OP_RET = 0xc3;
bool isOk = false;
uint64_t raw = this->getTargetRaw(index, isOk);
if (raw == INVALID_ADDR || !isOk) return false;
BYTE *cntnt = m_PE->getContent();
if (cntnt[raw] == OP_RET) {
return true;
}
return false;
}
//-------------------------