Skip to content

Instantly share code, notes, and snippets.

@koemeet
Last active November 5, 2017 18:28
Show Gist options
  • Save koemeet/618f7c8ad12c2fec21f17ea6d590e4b6 to your computer and use it in GitHub Desktop.
Save koemeet/618f7c8ad12c2fec21f17ea6d590e4b6 to your computer and use it in GitHub Desktop.
Dynamic recursive pointer scanner
#include <iostream>
#include "Scanner.h"
using namespace std;
int main() {
std::cout << "============= CHANSELISEE SCANNER ==============" << std::endl;
uintptr_t somePointer = 0x0000394884E; // put some pointer to for example your local player here
// start scanning from some base pointer. scan results are stored in scan_1.txt
Scanner scanner(somePointer, "scan_1.txt");
scanner.setLevel(4); // max recursion level
scanner.setMaxOffset(0x600); // max offset per structure
// this callback will be used to check if the current offset path needs to be saved
scanner.setCallback([](uintptr_t address, void *data) -> bool {
int teamId = *reinterpret_cast<int*>(data);
// in this example the scan gets all offsets which have the value `1`. this will of course yiels a lot of offsets.
// the idea here is to save those results and do a second scan when you have rejoined in a different team.
if (teamId == 1) {
return true;
}
return false;
});
// the first time you scan, don't provide any arguments, it will do a full scan.
scanner.scan();
// the 2th+ times provide the latest scanfile, so you can filter out paths and ultimately find your offset path!
// scanner.scan("scan_1.txt");
scanner.printFoundOffsets();
return 0;
}
#include "Scanner.h"
#include <sstream>
#include <fstream>
Scanner::Scanner(uintptr_t base, char* outputFile) : base(base), outputFile(outputFile)
{
}
void Scanner::scan(char *compareScan)
{
cout << "Scanning..." << endl;
if (compareScan) {
// read scan file
std::ifstream input;
input.open(compareScan);
std::string line;
while (getline(input, line)) {
std::istringstream ss(line);
std::string token;
vector<int> path;
while (std::getline(ss, token, ',')) {
path.push_back(stoi(token));
}
offsetsCompare.push_back(path);
}
scanStructureCompare();
}
else {
scanStructure(base);
}
cout << "Found paths: " << offsetsFound.size() << endl;
cout << "Scanned addresses: " << scanCount << endl;
// write scan file
std::ofstream fs;
fs.open(outputFile, std::ofstream::out | std::ofstream::in | std::ofstream::trunc);
for (auto offsetPath : offsetsFound) {
std::stringstream ss;
for (int i = 0; i < offsetPath.size(); i++) {
if (i > 0) {
ss << ",";
}
ss << offsetPath[i];
}
fs << ss.str() << endl;
}
fs.close();
cout << "Written to file" << endl;
}
void Scanner::scanStructureCompare()
{
/*for (auto offsets : offsetsCompare) {
uintptr_t address = base;
for (auto i = 0; i < offsets.size(); i++) {
if (i == offsets.size() - 1)
{
if (callback(address + offsets[i])) {
offsetsFound.push_back(offsets);
}
break;
}
address = Read<uintptr_t>(address + offsets[i]);
}
}*/
}
void Scanner::scanStructure(uintptr_t address, int level)
{
scanCount++;
// skip if we exceed recursion limit
if (level > this->level)
{
return;
}
level++;
// skip already processed addresses
//if (processed.find(address) != processed.end())
//{
// return;
//}
auto data = std::vector<byte>(maxOffset+0x4);
Read(address, maxOffset, data.data());
auto found = false;
for (auto offset = 0; offset <= maxOffset; offset += 0x4)
{
if (level == 1)
{
printf("Offset: %x\n", offset);
}
auto pointer = *reinterpret_cast<uintptr_t*>(&data[offset]);
// add current offset to current offset path
currentPath.push_back(offset);
// check if this pointer agrees to the user-defined check
if (callback(address + offset, &data[offset])) {
offsetsFound.push_back(currentPath);
std::stringstream ss;
for (int i = 0; i < currentPath.size(); i++) {
if (i > 0) {
ss << "] + ";
}
ss << "0x" << hex << currentPath[i];
}
cout << "Offset path: " << ss.str() << endl;
found = true;
}
// if it is a pointer, recursively scan it
if (pointer > 0x100000 && pointer < 0x7fffffffffff) {
scanStructure(pointer, level);
}
// we are leaving this offset, time to pop it
currentPath.pop_back();
}
// we have fully processed this whole address tree
//if (!found)
//{
// processed.emplace(address);
//}
}
void Scanner::printFoundOffsets()
{
for (auto offsetPath : offsetsFound) {
std::stringstream ss;
for (int i = 0; i < offsetPath.size(); i++) {
if (i > 0) {
ss << "] + ";
}
ss << "0x" << hex << offsetPath[i];
}
cout << "Offset path: " << ss.str() << endl;
}
}
#pragma once
#include <memory>
#include <iostream>
#include <unordered_set>
#include <vector>
#include <functional>
#include "../Memory/MemoryAware.h"
using namespace std;
class Scanner : protected Common::Memory::MemoryAware
{
protected:
uintptr_t base;
char* outputFile;
function<bool(uintptr_t, void*)> callback;
int level = 1;
int maxOffset = 0x800;
int64_t scanCount = 0;
unordered_set<uintptr_t> processed;
vector<int> currentPath;
vector<vector<int>> offsetsFound;
vector<vector<int>> offsetsCompare;
public:
Scanner(uintptr_t base, char* outputFile);
void scan(char *compareScan = nullptr);
void scanStructureCompare();
void setLevel(int level)
{
this->level = level;
}
void setMaxOffset(int maxOffset)
{
this->maxOffset = maxOffset;
}
void setCallback(function<bool(uintptr_t, void*)> f)
{
callback = f;
}
vector<vector<int>> getFoundOffsets()
{
return offsetsFound;
}
void printFoundOffsets();
protected:
void scanStructure(uintptr_t address, int level = 0);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment