/* Copyright (c) 2013-2017 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include DEFINE_VECTOR(mCoreMemorySearchResults, struct mCoreMemorySearchResult); static bool _op(int32_t value, int32_t match, enum mCoreMemorySearchOp op) { switch (op) { case mCORE_MEMORY_SEARCH_GREATER: return value > match; case mCORE_MEMORY_SEARCH_LESS: return value < match; case mCORE_MEMORY_SEARCH_EQUAL: case mCORE_MEMORY_SEARCH_DELTA: return value == match; } return false; } static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint32_t value32, enum mCoreMemorySearchOp op, struct mCoreMemorySearchResults* out, size_t limit) { const uint32_t* mem32 = mem; size_t found = 0; uint32_t start = block->start; uint32_t end = size; // TODO: Segments size_t i; // TODO: Big endian for (i = 0; (!limit || found < limit) && i < end; i += 4) { if (_op(mem32[i >> 2], value32, op)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i; res->type = mCORE_MEMORY_SEARCH_INT; res->width = 4; res->segment = -1; // TODO res->guessDivisor = 1; res->guessMultiplier = 1; res->oldValue = value32; ++found; } } return found; } static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint16_t value16, enum mCoreMemorySearchOp op, struct mCoreMemorySearchResults* out, size_t limit) { const uint16_t* mem16 = mem; size_t found = 0; uint32_t start = block->start; uint32_t end = size; // TODO: Segments size_t i; // TODO: Big endian for (i = 0; (!limit || found < limit) && i < end; i += 2) { if (_op(mem16[i >> 1], value16, op)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i; res->type = mCORE_MEMORY_SEARCH_INT; res->width = 2; res->segment = -1; // TODO res->guessDivisor = 1; res->guessMultiplier = 1; res->oldValue = value16; ++found; } } return found; } static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint8_t value8, enum mCoreMemorySearchOp op, struct mCoreMemorySearchResults* out, size_t limit) { const uint8_t* mem8 = mem; size_t found = 0; uint32_t start = block->start; uint32_t end = size; // TODO: Segments size_t i; for (i = 0; (!limit || found < limit) && i < end; ++i) { if (_op(mem8[i], value8, op)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i; res->type = mCORE_MEMORY_SEARCH_INT; res->width = 1; res->segment = -1; // TODO res->guessDivisor = 1; res->guessMultiplier = 1; res->oldValue = value8; ++found; } } return found; } static size_t _searchInt(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit) { if (params->align == params->width || params->align == -1) { switch (params->width) { case 4: return _search32(mem, size, block, params->valueInt, params->op, out, limit); case 2: return _search16(mem, size, block, params->valueInt, params->op, out, limit); case 1: return _search8(mem, size, block, params->valueInt, params->op, out, limit); } } return 0; } static size_t _searchStr(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const char* valueStr, int len, struct mCoreMemorySearchResults* out, size_t limit) { const char* memStr = mem; size_t found = 0; uint32_t start = block->start; uint32_t end = size; // TODO: Segments size_t i; for (i = 0; (!limit || found < limit) && i < end - len; ++i) { if (!memcmp(valueStr, &memStr[i], len)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i; res->type = mCORE_MEMORY_SEARCH_STRING; res->width = len; res->segment = -1; // TODO ++found; } } return found; } static size_t _searchGuess(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit) { // TODO: As str char* end; int64_t value; size_t found = 0; struct mCoreMemorySearchResults tmp; mCoreMemorySearchResultsInit(&tmp, 0); // Decimal: value = strtoll(params->valueStr, &end, 10); if (end && !end[0]) { if ((params->width == -1 && value > 0x10000) || params->width == 4) { found += _search32(mem, size, block, value, params->op, out, limit ? limit - found : 0); } else if ((params->width == -1 && value > 0x100) || params->width == 2) { found += _search16(mem, size, block, value, params->op, out, limit ? limit - found : 0); } else { found += _search8(mem, size, block, value, params->op, out, limit ? limit - found : 0); } uint32_t divisor = 1; while (value && !(value % 10)) { mCoreMemorySearchResultsClear(&tmp); value /= 10; divisor *= 10; if ((params->width == -1 && value > 0x10000) || params->width == 4) { found += _search32(mem, size, block, value, params->op, &tmp, limit ? limit - found : 0); } else if ((params->width == -1 && value > 0x100) || params->width == 2) { found += _search16(mem, size, block, value, params->op, &tmp, limit ? limit - found : 0); } else { found += _search8(mem, size, block, value, params->op, &tmp, limit ? limit - found : 0); } size_t i; for (i = 0; i < mCoreMemorySearchResultsSize(&tmp); ++i) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsGetPointer(&tmp, i); res->guessDivisor = divisor; *mCoreMemorySearchResultsAppend(out) = *res; } } } // Hex: value = strtoll(params->valueStr, &end, 16); if (end && !end[0]) { if ((params->width == -1 && value > 0x10000) || params->width == 4) { found += _search32(mem, size, block, value, params->op, out, limit ? limit - found : 0); } else if ((params->width == -1 && value > 0x100) || params->width == 2) { found += _search16(mem, size, block, value, params->op, out, limit ? limit - found : 0); } else { found += _search8(mem, size, block, value, params->op, out, limit ? limit - found : 0); } uint32_t divisor = 1; while (value && !(value & 0xF)) { mCoreMemorySearchResultsClear(&tmp); value >>= 4; divisor <<= 4; if ((params->width == -1 && value > 0x10000) || params->width == 4) { found += _search32(mem, size, block, value, params->op, &tmp, limit ? limit - found : 0); } else if ((params->width == -1 && value > 0x100) || params->width == 2) { found += _search16(mem, size, block, value, params->op, &tmp, limit ? limit - found : 0); } else { found += _search8(mem, size, block, value, params->op, &tmp, limit ? limit - found : 0); } size_t i; for (i = 0; i < mCoreMemorySearchResultsSize(&tmp); ++i) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsGetPointer(&tmp, i); res->guessDivisor = divisor; *mCoreMemorySearchResultsAppend(out) = *res; } } } mCoreMemorySearchResultsDeinit(&tmp); return found; } static size_t _search(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit) { switch (params->type) { case mCORE_MEMORY_SEARCH_INT: return _searchInt(mem, size, block, params, out, limit); case mCORE_MEMORY_SEARCH_STRING: return _searchStr(mem, size, block, params->valueStr, params->width, out, limit); case mCORE_MEMORY_SEARCH_GUESS: return _searchGuess(mem, size, block, params, out, limit); } return 0; } void mCoreMemorySearch(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit) { const struct mCoreMemoryBlock* blocks; size_t nBlocks = core->listMemoryBlocks(core, &blocks); size_t found = 0; size_t b; for (b = 0; (!limit || found < limit) && b < nBlocks; ++b) { size_t size; const struct mCoreMemoryBlock* block = &blocks[b]; if (!(block->flags & params->memoryFlags)) { continue; } void* mem = core->getMemoryBlock(core, block->id, &size); if (!mem) { continue; } if (size > block->end - block->start) { size = block->end - block->start; // TOOD: Segments } found += _search(mem, size, block, params, out, limit ? limit - found : 0); } } bool _testGuess(struct mCore* core, struct mCoreMemorySearchResult* res, const struct mCoreMemorySearchParams* params) { int64_t value; int32_t offset = 0; char* end; if (params->op == mCORE_MEMORY_SEARCH_DELTA) { offset = res->oldValue; } value = strtoll(params->valueStr, &end, 10); if (end) { res->oldValue += value; if (_op(core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) { return true; } if (!(res->address & 1) && (res->width >= 2 || res->width == -1) && _op(core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) { return true; } if (!(res->address & 3) && (res->width >= 4 || res->width == -1) && _op(core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) { return true; } res->oldValue -= value; } value = strtoll(params->valueStr, &end, 16); if (end) { res->oldValue += value; if (_op(core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) { return true; } if (!(res->address & 1) && (res->width >= 2 || res->width == -1) && _op(core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) { return true; } if (!(res->address & 3) && (res->width >= 4 || res->width == -1) && _op(core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) { return true; } res->oldValue -= value; } return false; } void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* inout) { size_t i; for (i = 0; i < mCoreMemorySearchResultsSize(inout); ++i) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsGetPointer(inout, i); switch (res->type) { case mCORE_MEMORY_SEARCH_INT: if (params->type == mCORE_MEMORY_SEARCH_GUESS) { if (!_testGuess(core, res, params)) { *res = *mCoreMemorySearchResultsGetPointer(inout, mCoreMemorySearchResultsSize(inout) - 1); mCoreMemorySearchResultsResize(inout, -1); --i; } } else if (params->type == mCORE_MEMORY_SEARCH_INT) { int32_t oldValue = params->valueInt; if (params->op == mCORE_MEMORY_SEARCH_DELTA) { oldValue += res->oldValue; } int32_t value = 0; switch (params->width) { case 1: value = core->rawRead8(core, res->address, res->segment); break; case 2: value = core->rawRead16(core, res->address, res->segment); break; case 4: value = core->rawRead32(core, res->address, res->segment); break; default: break; } if (!_op(value, oldValue, params->op)) { *res = *mCoreMemorySearchResultsGetPointer(inout, mCoreMemorySearchResultsSize(inout) - 1); mCoreMemorySearchResultsResize(inout, -1); --i; } else { res->oldValue = value; } } break; case mCORE_MEMORY_SEARCH_STRING: case mCORE_MEMORY_SEARCH_GUESS: // TOOD break; } } }