/* 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 size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint32_t value32, 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 += 16) { int mask = 0; mask |= (mem32[(i >> 2) + 0] == value32) << 0; mask |= (mem32[(i >> 2) + 1] == value32) << 1; mask |= (mem32[(i >> 2) + 2] == value32) << 2; mask |= (mem32[(i >> 2) + 3] == value32) << 3; if (!mask) { continue; } if ((mask & 1) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i; res->type = mCORE_MEMORY_SEARCH_32; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 2) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 4; res->type = mCORE_MEMORY_SEARCH_32; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 4) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 8; res->type = mCORE_MEMORY_SEARCH_32; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 8) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 12; res->type = mCORE_MEMORY_SEARCH_32; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } } // TODO: last 12 bytes return found; } static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint16_t value16, 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 += 16) { int mask = 0; mask |= (mem16[(i >> 1) + 0] == value16) << 0; mask |= (mem16[(i >> 1) + 1] == value16) << 1; mask |= (mem16[(i >> 1) + 2] == value16) << 2; mask |= (mem16[(i >> 1) + 3] == value16) << 3; mask |= (mem16[(i >> 1) + 4] == value16) << 4; mask |= (mem16[(i >> 1) + 5] == value16) << 5; mask |= (mem16[(i >> 1) + 6] == value16) << 6; mask |= (mem16[(i >> 1) + 7] == value16) << 7; if (!mask) { continue; } if ((mask & 1) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 2) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 2; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 4) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 4; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 8) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 6; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 16) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 8; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 32) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 10; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 64) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 12; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 128) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 14; res->type = mCORE_MEMORY_SEARCH_16; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } } // TODO: last 14 bytes return found; } static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint8_t value8, 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 += 8) { int mask = 0; mask |= (mem8[i + 0] == value8) << 0; mask |= (mem8[i + 1] == value8) << 1; mask |= (mem8[i + 2] == value8) << 2; mask |= (mem8[i + 3] == value8) << 3; mask |= (mem8[i + 4] == value8) << 4; mask |= (mem8[i + 5] == value8) << 5; mask |= (mem8[i + 6] == value8) << 6; mask |= (mem8[i + 7] == value8) << 7; if (!mask) { continue; } if ((mask & 1) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 2) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 1; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 4) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 2; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 8) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 3; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 16) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 4; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 32) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 5; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 64) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 6; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } if ((mask & 128) && (!limit || found < limit)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i + 7; res->type = mCORE_MEMORY_SEARCH_8; res->segment = -1; // TODO res->guessDivisor = 1; ++found; } } // TODO: last 7 bytes return found; } static size_t _searchStr(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const char* valueStr, struct mCoreMemorySearchResults* out, size_t limit) { const char* memStr = mem; size_t found = 0; size_t len = strlen(valueStr); 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 (!strncmp(valueStr, &memStr[i], len)) { struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out); res->address = start + i; res->type = mCORE_MEMORY_SEARCH_STRING; res->segment = -1; // TODO ++found; } } return found; } static size_t _searchGuess(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const char* valueStr, struct mCoreMemorySearchResults* out, size_t limit) { // TODO: As str char* end; uint64_t value; size_t found = 0; struct mCoreMemorySearchResults tmp; mCoreMemorySearchResultsInit(&tmp, 0); // Decimal: value = strtoull(valueStr, &end, 10); if (end && !end[0]) { if (value > 0x10000) { found += _search32(mem, size, block, value, out, limit ? limit - found : 0); } else if (value > 0x100) { found += _search16(mem, size, block, value, out, limit ? limit - found : 0); } else { found += _search8(mem, size, block, value, out, limit ? limit - found : 0); } uint32_t divisor = 1; while (value && !(value % 10)) { mCoreMemorySearchResultsClear(&tmp); value /= 10; divisor *= 10; if (value > 0x10000) { found += _search32(mem, size, block, value, &tmp, limit ? limit - found : 0); } else if (value > 0x100) { found += _search16(mem, size, block, value, &tmp, limit ? limit - found : 0); } else { found += _search8(mem, size, block, value, &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 = strtoull(valueStr, &end, 16); if (end && !end[0]) { if (value > 0x10000) { found += _search32(mem, size, block, value, out, limit ? limit - found : 0); } else if (value > 0x100) { found += _search16(mem, size, block, value, out, limit ? limit - found : 0); } else { found += _search8(mem, size, block, value, out, limit ? limit - found : 0); } uint32_t divisor = 1; while (value && !(value & 0xF)) { mCoreMemorySearchResultsClear(&tmp); value >>= 4; divisor <<= 4; if (value > 0x10000) { found += _search32(mem, size, block, value, &tmp, limit ? limit - found : 0); } else if (value > 0x100) { found += _search16(mem, size, block, value, &tmp, limit ? limit - found : 0); } else { found += _search8(mem, size, block, value, &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_32: return _search32(mem, size, block, params->value32, out, limit); case mCORE_MEMORY_SEARCH_16: return _search16(mem, size, block, params->value16, out, limit); case mCORE_MEMORY_SEARCH_8: return _search8(mem, size, block, params->value8, out, limit); case mCORE_MEMORY_SEARCH_STRING: return _searchStr(mem, size, block, params->valueStr, out, limit); case mCORE_MEMORY_SEARCH_GUESS: return _searchGuess(mem, size, block, params->valueStr, out, limit); } } 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, const struct mCoreMemorySearchResult* res, const struct mCoreMemorySearchParams* params) { uint64_t value; char* end; value = strtoull(params->valueStr, &end, 10); if (end) { if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor == value) { return true; } if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor == value) { return true; } if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor == value) { return true; } } value = strtoull(params->valueStr, &end, 16); if (end) { if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor == value) { return true; } if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor == value) { return true; } if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor == value) { return true; } } 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_8: switch (params->type) { case mCORE_MEMORY_SEARCH_8: if (core->rawRead8(core, res->address, res->segment) != params->value8) { mCoreMemorySearchResultsShift(inout, i, 1); --i; } break; case mCORE_MEMORY_SEARCH_16: if (core->rawRead8(core, res->address, res->segment) != params->value16) { mCoreMemorySearchResultsShift(inout, i, 1); --i; } break; case mCORE_MEMORY_SEARCH_32: if (core->rawRead32(core, res->address, res->segment) != params->value32) { mCoreMemorySearchResultsShift(inout, i, 1); --i; } break; case mCORE_MEMORY_SEARCH_GUESS: if (!_testGuess(core, res, params)) { mCoreMemorySearchResultsShift(inout, i, 1); --i; } break; default: break; } break; case mCORE_MEMORY_SEARCH_16: switch (params->type) { case mCORE_MEMORY_SEARCH_16: if (core->rawRead16(core, res->address, res->segment) != params->value16) { mCoreMemorySearchResultsShift(inout, i, 1); --i; } break; case mCORE_MEMORY_SEARCH_32: if (core->rawRead32(core, res->address, res->segment) != params->value32) { mCoreMemorySearchResultsShift(inout, i, 1); --i; } break; case mCORE_MEMORY_SEARCH_GUESS: if (!_testGuess(core, res, params)) { mCoreMemorySearchResultsShift(inout, i, 1); --i; } break; default: break; } break; case mCORE_MEMORY_SEARCH_32: switch (params->type) { case mCORE_MEMORY_SEARCH_32: if (core->rawRead32(core, res->address, res->segment) != params->value32) { mCoreMemorySearchResultsShift(inout, i, 1); --i; } break; case mCORE_MEMORY_SEARCH_GUESS: if (!_testGuess(core, res, params)) { mCoreMemorySearchResultsShift(inout, i, 1); --i; } break; default: break; } break; case mCORE_MEMORY_SEARCH_STRING: case mCORE_MEMORY_SEARCH_GUESS: // TOOD break; } } }