Android Pattern/Signature Scanning (Source)

So in this thread I will explain some things about how to create these patterns and use them in your hack alongside with the source.

This source and tutorial is not il2cpp only and can be applied in other games too.
But in this tutorial we will use an il2cpp game. Forward Assault.

Why? We will be using IDA to create the patterns and il2cppdumper gives us python scripts to understand the code better.

Basically without patternscanning and without using the il2cpp api we would have to update offsets every time the game updates. And with some games, this is a tedious task.

But that’s where patternscanning comes in handy. I will not explain how it works.
If you want to get a better understanding of patternscanning here is a good resource I’ve learned from.

First we need this plugin to create and test the patterns.

So basically fire up ida and load in the library. In my case libil2cpp.so. Because it’s an il2cpp game I can get the function names and structures by loading the scripts il2cpp dumper created.

Now I will search for the method I want to patch/hook whatever.
I want to hook the function Update in the Player class so I search for Player$$Update

Select a few instructions and open Edit > Plugins > Sigmaker

When its open select Create IDA pattern from selection and click OK

grafik

Now you should see the pattern in the Output Window

grafik

Once again open the SigMaker plugin. But this time you select Test ida pattern then again click OK

grafik

You see that something gets printed in the Output Window

grafik

Nice. This is what you want to see. Only one sig. This should match the offset found in the dummy dll’s or in the dump.cs file

grafik

And it certainly does. Awesome.

Now we need to use the pattern in our code?
How can you do that? Its as simple as this:


player_update_offset should return the same uintptr_t as get_absolute_address with the offset.

//mem.h
//made by Octowolve
/*
    mem.h - a c++ header for android memory
    Copyright (C) 2020  Octowolve

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
#pragma once
#include <stdint.h>
#include <string>

namespace mem {
    struct module_info {
        uintptr_t start_address;
        uintptr_t end_address;
        intptr_t size;
        std::string name;
    };

    inline module_info get_module_info(const char* module_name)
	{
		std::unique_ptr<FILE, decltype(&fclose)> maps_handle(fopen("/proc/self/maps", "r"), &fclose);
		char line[512], mod_name[64];
		module_info mod_info{};
		while (fgets(line, sizeof(line), maps_handle.get()))
			if (std::sscanf(line, "%x-%x %*s %*ld %*s %*d %s", &mod_info.start_address, &mod_info.end_address, mod_name)) {
				if (std::strstr(mod_name, module_name)) {
					mod_info.size = mod_info.end_address - mod_info.start_address;

					if (mod_info.name.empty())
						mod_info.name = std::string(mod_name);

					return mod_info;
				}
			}
		return module_info();
	}

	inline uintptr_t find_pattern(uint8_t* start, const size_t length, const char* pattern) {
		const char* pat = pattern;
		uint8_t* first_match = 0;
		for (auto current_byte = start; current_byte < (start + length); ++current_byte) {
			if (*pat == '?' || *current_byte == strtoul(pat, NULL, 16)) {
				if (!first_match)
					first_match = current_byte;
				if (!pat[2])
					return (uintptr_t)first_match;
				pat += *(uint16_t*)pat == 16191 || *pat != '?' ? 3 : 2;
			}
			else if (first_match) {
				current_byte = first_match;
				pat = pattern;
				first_match = 0;
			}
		} return 0;
	}

	inline uintptr_t get_absolute_address(uintptr_t relativeAddr, const char* libraryName = "libil2cpp.so") {
		if (auto lib_base = get_module_info(libraryName).start_address)
			return (reinterpret_cast<uintptr_t>(lib_base + relativeAddr));
		else
			return 0;
	}

	inline uintptr_t find_pattern_in_module(std::string module_name, std::string pattern) {
		module_info mod_info = get_module_info(module_name.c_str());
		return find_pattern((uint8_t*)mod_info.start_address, mod_info.size, pattern.c_str());
	}
}

5 Likes

First heheheh, very sexy tutorial >:))

1 Like

Niceo tutorial (;-;}

1 Like

Nice one! Thanks for sharing!

1 Like

Gud Gud, Very Gud, Super Guuuuuud ⌐╦╦═─

1 Like

Good one bro thanks for sharing:)