parent
a40d10c21c
commit
edd689b4db
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,133 @@
|
|||||||
|
|
||||||
|
local metatable = {}
|
||||||
|
local rawget = rawget
|
||||||
|
local setmetatable = setmetatable
|
||||||
|
local import_type = xlua.import_type
|
||||||
|
local import_generic_type = xlua.import_generic_type
|
||||||
|
local load_assembly = xlua.load_assembly
|
||||||
|
|
||||||
|
function metatable:__index(key)
|
||||||
|
local fqn = rawget(self,'.fqn')
|
||||||
|
fqn = ((fqn and fqn .. '.') or '') .. key
|
||||||
|
|
||||||
|
local obj = import_type(fqn)
|
||||||
|
|
||||||
|
if obj == nil then
|
||||||
|
-- It might be an assembly, so we load it too.
|
||||||
|
obj = { ['.fqn'] = fqn }
|
||||||
|
setmetatable(obj, metatable)
|
||||||
|
elseif obj == true then
|
||||||
|
return rawget(self, key)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Cache this lookup
|
||||||
|
rawset(self, key, obj)
|
||||||
|
return obj
|
||||||
|
end
|
||||||
|
|
||||||
|
function metatable:__newindex()
|
||||||
|
error('No such type: ' .. rawget(self,'.fqn'), 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- A non-type has been called; e.g. foo = System.Foo()
|
||||||
|
function metatable:__call(...)
|
||||||
|
local n = select('#', ...)
|
||||||
|
local fqn = rawget(self,'.fqn')
|
||||||
|
if n > 0 then
|
||||||
|
local gt = import_generic_type(fqn, ...)
|
||||||
|
if gt then
|
||||||
|
return rawget(CS, gt)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error('No such type: ' .. fqn, 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
CS = CS or {}
|
||||||
|
setmetatable(CS, metatable)
|
||||||
|
|
||||||
|
typeof = function(t) return t.UnderlyingSystemType end
|
||||||
|
cast = xlua.cast
|
||||||
|
if not setfenv or not getfenv then
|
||||||
|
local function getfunction(level)
|
||||||
|
local info = debug.getinfo(level + 1, 'f')
|
||||||
|
return info and info.func
|
||||||
|
end
|
||||||
|
|
||||||
|
function setfenv(fn, env)
|
||||||
|
if type(fn) == 'number' then fn = getfunction(fn + 1) end
|
||||||
|
local i = 1
|
||||||
|
while true do
|
||||||
|
local name = debug.getupvalue(fn, i)
|
||||||
|
if name == '_ENV' then
|
||||||
|
debug.upvaluejoin(fn, i, (function()
|
||||||
|
return env
|
||||||
|
end), 1)
|
||||||
|
break
|
||||||
|
elseif not name then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return fn
|
||||||
|
end
|
||||||
|
|
||||||
|
function getfenv(fn)
|
||||||
|
if type(fn) == 'number' then fn = getfunction(fn + 1) end
|
||||||
|
local i = 1
|
||||||
|
while true do
|
||||||
|
local name, val = debug.getupvalue(fn, i)
|
||||||
|
if name == '_ENV' then
|
||||||
|
return val
|
||||||
|
elseif not name then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
xlua.hotfix = function(cs, field, func)
|
||||||
|
if func == nil then func = false end
|
||||||
|
local tbl = (type(field) == 'table') and field or {[field] = func}
|
||||||
|
for k, v in pairs(tbl) do
|
||||||
|
local cflag = ''
|
||||||
|
if k == '.ctor' then
|
||||||
|
cflag = '_c'
|
||||||
|
k = 'ctor'
|
||||||
|
end
|
||||||
|
local f = type(v) == 'function' and v or nil
|
||||||
|
xlua.access(cs, cflag .. '__Hotfix0_'..k, f) -- at least one
|
||||||
|
pcall(function()
|
||||||
|
for i = 1, 99 do
|
||||||
|
xlua.access(cs, cflag .. '__Hotfix'..i..'_'..k, f)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
xlua.private_accessible(cs)
|
||||||
|
end
|
||||||
|
xlua.getmetatable = function(cs)
|
||||||
|
return xlua.metatable_operation(cs)
|
||||||
|
end
|
||||||
|
xlua.setmetatable = function(cs, mt)
|
||||||
|
return xlua.metatable_operation(cs, mt)
|
||||||
|
end
|
||||||
|
xlua.setclass = function(parent, name, impl)
|
||||||
|
impl.UnderlyingSystemType = parent[name].UnderlyingSystemType
|
||||||
|
rawset(parent, name, impl)
|
||||||
|
end
|
||||||
|
|
||||||
|
local base_mt = {
|
||||||
|
__index = function(t, k)
|
||||||
|
local csobj = t['__csobj']
|
||||||
|
local func = csobj['<>xLuaBaseProxy_'..k]
|
||||||
|
return function(_, ...)
|
||||||
|
return func(csobj, ...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
base = function(csobj)
|
||||||
|
return setmetatable({__csobj = csobj}, base_mt)
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,73 @@
|
|||||||
|
#include "bypass.h"
|
||||||
|
|
||||||
|
namespace ligma
|
||||||
|
{
|
||||||
|
namespace bypass
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// you might need to change your paths for dlopen!
|
||||||
|
//
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
fopen_ptr = dlsym(dlopen("libc.so", RTLD_NOLOAD), "fopen");
|
||||||
|
system_prop_get = dlsym(dlopen("libc.so", RTLD_NOLOAD), "__system_property_get");
|
||||||
|
loadbufferx = dlsym(dlopen("libxlua.so", RTLD_NOW), "luaL_loadbufferx");
|
||||||
|
ligma::hook::make_hook(loadbufferx, reinterpret_cast<void*>(&loadbufferx_hook));
|
||||||
|
ligma::hook::make_hook(fopen_ptr, reinterpret_cast<void*>(&fopen_hook));
|
||||||
|
ligma::hook::make_hook(system_prop_get, reinterpret_cast<void*>(&system_property_hook));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// dont let a single lua script load!
|
||||||
|
//
|
||||||
|
int loadbufferx_hook(void* L, const char* buff, size_t sz, const char* name, const char* mode)
|
||||||
|
{ return NULL; }
|
||||||
|
|
||||||
|
//
|
||||||
|
// the first module loaded by default is libtprt.so, it opens base.apk and checks its MD5.
|
||||||
|
// we make it open the original apk :)
|
||||||
|
//
|
||||||
|
__attribute__((noinline))
|
||||||
|
FILE* fopen_hook(const char* path, const char* mode)
|
||||||
|
{
|
||||||
|
if (strstr(path, "base.apk"))
|
||||||
|
{
|
||||||
|
path = "/data/app/base_orig.apk";
|
||||||
|
LOGI("spoofed base.apk to original apk!");
|
||||||
|
}
|
||||||
|
|
||||||
|
fopen_mutex.lock();
|
||||||
|
ligma::hook::disable(fopen_ptr);
|
||||||
|
const auto result = fopen(path, mode);
|
||||||
|
ligma::hook::enable(fopen_ptr);
|
||||||
|
fopen_mutex.unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// spoof all hwids to "what do you call nuts on your chin? a dick down your throat you fucking retard!"
|
||||||
|
//
|
||||||
|
__attribute__((noinline))
|
||||||
|
int system_property_hook(const char* name, char* value)
|
||||||
|
{
|
||||||
|
system_prop_mutex.lock();
|
||||||
|
ligma::hook::disable(system_prop_get);
|
||||||
|
__system_property_get(name, value);
|
||||||
|
ligma::hook::enable(system_prop_get);
|
||||||
|
system_prop_mutex.unlock();
|
||||||
|
|
||||||
|
//
|
||||||
|
// dont spoof persist.sys.timezone or these other ones.
|
||||||
|
//
|
||||||
|
if (strcmp(name, "persist.sys.timezone") != 0 &&
|
||||||
|
strcmp(name, "ro.build.fingerprint") != 0 &&
|
||||||
|
strcmp(name, "ro.revision") != 0 &&
|
||||||
|
strcmp(name, "ro.build.version.sdk") != 0)
|
||||||
|
{
|
||||||
|
LOGI("spoofed hwid = %s, to = %s", value, HWID_VALUE);
|
||||||
|
value = HWID_VALUE;
|
||||||
|
}
|
||||||
|
return strlen(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
#include <elf.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <map>
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
#define LOGI(...) ((void)__android_log_print(4, "ligma", __VA_ARGS__))
|
||||||
|
#define LOGW(...) ((void)__android_log_print(5, "ligma", __VA_ARGS__))
|
||||||
|
|
||||||
|
namespace ligma
|
||||||
|
{
|
||||||
|
namespace hook
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// TODO this doesnt work yet, needs to be debugged!
|
||||||
|
//
|
||||||
|
inline void* got_hook(elf32_hdr* module_base, const std::pair<const char*, const char*>& module_info, void* new_ptr)
|
||||||
|
{
|
||||||
|
if (!module_base || !module_info.first || !module_info.second || !new_ptr)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const auto orig_module_base = dlopen(module_info.first, RTLD_NOW);
|
||||||
|
const auto orig_ptr = dlsym(orig_module_base, module_info.second);
|
||||||
|
|
||||||
|
const auto shstrtab_header_offset = module_base->e_shoff + module_base->e_shstrndx * sizeof(elf32_shdr);
|
||||||
|
const auto shstr_header = reinterpret_cast<elf32_shdr*>(reinterpret_cast<std::uintptr_t>(module_base) + shstrtab_header_offset);
|
||||||
|
|
||||||
|
const auto shstr_section = reinterpret_cast<const char*>(module_base) + shstr_header->sh_offset;
|
||||||
|
auto section_header = reinterpret_cast<elf32_shdr*>(reinterpret_cast<std::uintptr_t>(module_base) + module_base->e_shoff);
|
||||||
|
|
||||||
|
for (auto idx = 0u; idx < module_base->e_shnum; ++idx)
|
||||||
|
{
|
||||||
|
if (strcmp(shstr_section + section_header->sh_name, ".got"))
|
||||||
|
{
|
||||||
|
for (auto section_value = reinterpret_cast<std::uintptr_t>(module_base) + section_header->sh_offset;
|
||||||
|
section_value < reinterpret_cast<std::uintptr_t>(module_base) + section_header->sh_size; section_value += 0x8)
|
||||||
|
if (*reinterpret_cast<void**>(section_value) == orig_ptr)
|
||||||
|
*reinterpret_cast<void**>(section_value) = new_ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
section_header++;
|
||||||
|
}
|
||||||
|
return orig_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 xerox
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <map>
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#define PAGE_START(ptr) reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(ptr) >> 12 << 12)
|
||||||
|
#define ARM_JMP_CODE 0xE51FF004
|
||||||
|
|
||||||
|
namespace ligma
|
||||||
|
{
|
||||||
|
namespace hook
|
||||||
|
{
|
||||||
|
class detour
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
detour(void* addr_to_hook, void* jmp_to, bool enable = true)
|
||||||
|
:
|
||||||
|
hook_addr(addr_to_hook),
|
||||||
|
detour_addr(jmp_to),
|
||||||
|
hook_installed(false)
|
||||||
|
{
|
||||||
|
reinterpret_cast<std::uint32_t*>(jmp_code)[0] = ARM_JMP_CODE; // LDR PC, [PC, #-4]
|
||||||
|
reinterpret_cast<void**>(jmp_code)[1] = jmp_to;
|
||||||
|
memcpy(org_bytes, hook_addr, sizeof(org_bytes));
|
||||||
|
if (enable) install();
|
||||||
|
}
|
||||||
|
|
||||||
|
void install()
|
||||||
|
{
|
||||||
|
if (hook_installed.load())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||||
|
{
|
||||||
|
memcpy((void*)((long)hook_addr), jmp_code, sizeof(jmp_code));
|
||||||
|
mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_EXEC);
|
||||||
|
cacheflush(reinterpret_cast<long>(hook_addr), reinterpret_cast<long>(hook_addr) + getpagesize(), NULL);
|
||||||
|
hook_installed.exchange(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uninstall()
|
||||||
|
{
|
||||||
|
if (!hook_installed.load())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||||
|
{
|
||||||
|
memcpy(hook_addr, org_bytes, sizeof(jmp_code));
|
||||||
|
mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_EXEC);
|
||||||
|
cacheflush(reinterpret_cast<long>(hook_addr), reinterpret_cast<long>(hook_addr) + getpagesize(), NULL);
|
||||||
|
hook_installed.exchange(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~detour() { uninstall(); }
|
||||||
|
bool installed() { return hook_installed; }
|
||||||
|
void* hook_address() { return hook_addr; }
|
||||||
|
void* detour_address() { return detour_addr; }
|
||||||
|
private:
|
||||||
|
std::atomic<bool> hook_installed;
|
||||||
|
void* hook_addr, * detour_addr;
|
||||||
|
|
||||||
|
unsigned char jmp_code[8]{};
|
||||||
|
std::uint8_t org_bytes[sizeof(jmp_code)];
|
||||||
|
};
|
||||||
|
|
||||||
|
// this is jank, but needed because the OS isnt initalizing statics/inlined globals... :|
|
||||||
|
inline std::map<void*, std::unique_ptr<detour>>* get_hooks()
|
||||||
|
{
|
||||||
|
static std::map<void*, std::unique_ptr<detour>> hooks{};
|
||||||
|
return &hooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void make_hook(void* addr_to_hook, void* jmp_to_addr, bool enable = true)
|
||||||
|
{
|
||||||
|
if (!addr_to_hook)
|
||||||
|
return;
|
||||||
|
|
||||||
|
get_hooks()->insert({
|
||||||
|
addr_to_hook,
|
||||||
|
std::make_unique<detour>(
|
||||||
|
addr_to_hook,
|
||||||
|
jmp_to_addr,
|
||||||
|
enable
|
||||||
|
) }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void enable(void* addr)
|
||||||
|
{
|
||||||
|
if (!addr)
|
||||||
|
return;
|
||||||
|
get_hooks()->at(addr)->install();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void disable(void* addr)
|
||||||
|
{
|
||||||
|
if (!addr)
|
||||||
|
return;
|
||||||
|
get_hooks()->at(addr)->uninstall();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void remove(void* addr)
|
||||||
|
{
|
||||||
|
if (!addr)
|
||||||
|
return;
|
||||||
|
get_hooks()->erase(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <android/log.h>
|
||||||
|
#include "utils/utils.h"
|
||||||
|
#include "hooks/shithook.h"
|
||||||
|
#include "hooks/got_hook.h"
|
||||||
|
|
||||||
|
#define LOGI(...) ((void)__android_log_print(4, "ligma", __VA_ARGS__))
|
||||||
|
#define LOGW(...) ((void)__android_log_print(5, "ligma", __VA_ARGS__))
|
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <functional>
|
||||||
|
#include <fstream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace ligma
|
||||||
|
{
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
inline void iterate_memory(const std::function<void(const std::pair<std::uintptr_t, std::uintptr_t>&, const std::string& protection)>& callback)
|
||||||
|
{
|
||||||
|
std::fstream maps("/proc/self/maps");
|
||||||
|
std::pair<std::uintptr_t, std::uintptr_t> memory_range;
|
||||||
|
std::string page_perms;
|
||||||
|
while (maps >> memory_range.first >> memory_range.second >> page_perms)
|
||||||
|
{
|
||||||
|
maps.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // skip to next line :)
|
||||||
|
callback(memory_range, page_perms);
|
||||||
|
}
|
||||||
|
maps.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,74 +0,0 @@
|
|||||||
# build scripts
|
|
||||||
|
|
||||||
First things first, to get this compiling/working for you, you are going to need to fix these build scripts:
|
|
||||||
|
|
||||||
```
|
|
||||||
adb logcat -c
|
|
||||||
adb push C:\Users\%USERNAME%\source\repos\ligma\ARM\Release\libligma.so /data/app/com.activision.callofduty.shooter-1/lib/arm/libligma.so
|
|
||||||
start cmd /k "title 'ligma filter' & adb logcat | findstr ligma"
|
|
||||||
start cmd /k "title 'codm logs' & adb logcat | findstr com.activision.callofduty.shooter"
|
|
||||||
start cmd /k "title 'all logs' & adb logcat"
|
|
||||||
adb shell am start -n com.activision.callofduty.shooter/com.tencent.tmgp.cod.PermissionGrantActivity
|
|
||||||
```
|
|
||||||
|
|
||||||
just change `C:\Users\%USERNAME%\source\repos\ligma\ARM\Release\libligma.so` to the path of your repo. Also change `adb` to whatever `adb` your emulator is using.
|
|
||||||
|
|
||||||
# setup
|
|
||||||
|
|
||||||
Since we arent done making this cheat, we have no need to repackage the entire apk and reinstall everytime we wanna test our code. Since the application
|
|
||||||
is not inside of this repo, you will need to first download the apk from here: [cod mobile](https://apkpure.com/call-of-duty-legends-of-war/com.activision.callofduty.shooter).
|
|
||||||
|
|
||||||
### decompile
|
|
||||||
|
|
||||||
First unzip the xapk and take the .apk that is inside of it out. use apktool.jar to decompile the apk. we are going to patch a smali file to load our .so before any other .so.
|
|
||||||
|
|
||||||
```
|
|
||||||
apktool.jar d codm.apk
|
|
||||||
```
|
|
||||||
|
|
||||||
now go to this smali file: `smali\com\tencent\tpshell\TPShellApplication.smali`. Add this smali code to load our .so:
|
|
||||||
|
|
||||||
[`[WARNING]`]: (do not put libligma.so or ligma.so just ligma!)
|
|
||||||
|
|
||||||
```
|
|
||||||
const-string v0, "ligma"
|
|
||||||
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
|
|
||||||
```
|
|
||||||
|
|
||||||
<img src="https://imgur.com/5OcgEsB.png"/>
|
|
||||||
|
|
||||||
### recompile
|
|
||||||
|
|
||||||
simply run this to recompile the apk, this apk is not signed and will need to be signed.
|
|
||||||
|
|
||||||
```
|
|
||||||
apktool.jar b codm -o codm_patched.apk
|
|
||||||
```
|
|
||||||
|
|
||||||
### signing
|
|
||||||
|
|
||||||
use apksigner.jar to sign the newly compiled apk.
|
|
||||||
|
|
||||||
```
|
|
||||||
apksigner.jar -a codm_patched.apk
|
|
||||||
```
|
|
||||||
|
|
||||||
now you have a patched & signed apk. Its time to install the apk.
|
|
||||||
|
|
||||||
### install
|
|
||||||
|
|
||||||
now that we have a signed and patched apk, install the apk (not the xapk) just the patched apk into your emulator. After you have installed it you will
|
|
||||||
need to copy the .obb files which are located INSIDE of the xapk. open the xapk back up in zip, open `Android` folder and you will see an `obb` folder. Copy this folder
|
|
||||||
to `Android/obb (or copy the content from inside of the obb file to here)` on your emulator.
|
|
||||||
|
|
||||||
<img src="https://imgur.com/f35AYAA.png"/>
|
|
||||||
|
|
||||||
|
|
||||||
Finally you will now need to copy the original `apk` to `/data/app/` please refer to [this](https://githacks.org/android-reverse-engineering/cod-mobile/-/blob/master/ligma%20(cheat)/ligma/bypass/bypass.cpp#L35) line of code to understand why.
|
|
||||||
Ensure that the `apk` is named `base_orig.apk`. If everything is done correctly you will now be able to build your .so and the game will auto run.
|
|
||||||
|
|
||||||
# Result
|
|
||||||
|
|
||||||
now if you click build inside of visual studios your screen should look like this (make sure you build in release otherwise the build script wont know where to copy your .so from!). Also be aware that you may need to build 2/3 times since `adb` will connect the first time...
|
|
||||||
|
|
||||||
<img src="https://imgur.com/87wxbPL.png"/>
|
|
@ -1,106 +0,0 @@
|
|||||||
#include "bypass.h"
|
|
||||||
|
|
||||||
namespace ligma
|
|
||||||
{
|
|
||||||
namespace bypass
|
|
||||||
{
|
|
||||||
void init()
|
|
||||||
{
|
|
||||||
fopen_ptr = dlsym(dlopen("libc.so", RTLD_NOLOAD), "fopen");
|
|
||||||
system_prop_get = dlsym(dlopen("libc.so", RTLD_NOLOAD), "__system_property_get");
|
|
||||||
|
|
||||||
const auto cubehawk_base = reinterpret_cast<std::uintptr_t>(dlopen("libcubehawk.so", RTLD_LAZY));
|
|
||||||
const auto libtersafe_base = reinterpret_cast<std::uintptr_t>(dlopen("libtersafe.so", RTLD_LAZY));
|
|
||||||
|
|
||||||
shithook::make_hook(fopen_ptr, reinterpret_cast<void*>(&fopen_hook));
|
|
||||||
shithook::make_hook(reinterpret_cast<void*>(cubehawk_base + offset_emulator_check), reinterpret_cast<void*>(&emulator_check));
|
|
||||||
|
|
||||||
LOGI("disabled emulator checks....");
|
|
||||||
LOGI("disabled patch checks....");
|
|
||||||
|
|
||||||
shithook::make_hook(reinterpret_cast<void*>(libtersafe_base + offset_ischeat_packet), reinterpret_cast<void*>(&tss_sdk_ischeatpacket));
|
|
||||||
shithook::make_hook(system_prop_get, reinterpret_cast<void*>(&system_property_hook));
|
|
||||||
|
|
||||||
LOGI("disabled is cheat packet checks.....");
|
|
||||||
LOGI("disabled hwid checks.....");
|
|
||||||
|
|
||||||
shithook::make_hook(reinterpret_cast<void*>(cubehawk_base + offset_mshook_function), reinterpret_cast<void*>(&ms_hook_function));
|
|
||||||
LOGI("disabling all MSHookFunction calls! (no more back buffer hook!)");
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// the first module loaded by default is libtprt.so, it opens base.apk and checks its MD5.
|
|
||||||
//
|
|
||||||
__attribute__((noinline))
|
|
||||||
FILE* fopen_hook(const char* path, const char* mode)
|
|
||||||
{
|
|
||||||
LOGI("fopen called! path = %s, mode = %s", path, mode);
|
|
||||||
if (strstr(path, "base.apk"))
|
|
||||||
{
|
|
||||||
path = "/data/app/base_orig.apk";
|
|
||||||
LOGI("spoofing to original base.apk!");
|
|
||||||
}
|
|
||||||
|
|
||||||
fopen_mutex.lock();
|
|
||||||
shithook::disable(fopen_ptr);
|
|
||||||
const auto result = fopen(path, mode);
|
|
||||||
shithook::enable(fopen_ptr);
|
|
||||||
fopen_mutex.unlock();
|
|
||||||
|
|
||||||
LOGI("fopen result = %p", result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// the original function returns 1 if no emulator is found else a number associated with an emulator.
|
|
||||||
//
|
|
||||||
__attribute__((noinline))
|
|
||||||
signed int emulator_check(const char* a1, const char* a2)
|
|
||||||
{
|
|
||||||
LOGI("emulator check called.... spoofing emulator....");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// never send is cheat packet....
|
|
||||||
//
|
|
||||||
__attribute__((noinline))
|
|
||||||
int tss_sdk_ischeatpacket(int a1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// spoof all hwids to "what do you call nuts on your chin? a dick down your throat you fucking retard!"
|
|
||||||
//
|
|
||||||
__attribute__((noinline))
|
|
||||||
int system_property_hook(const char* name, char* value)
|
|
||||||
{
|
|
||||||
LOGI("trying to get HWID = %s", name);
|
|
||||||
system_prop_mutex.lock();
|
|
||||||
shithook::disable(system_prop_get);
|
|
||||||
__system_property_get(name, value);
|
|
||||||
shithook::enable(system_prop_get);
|
|
||||||
system_prop_mutex.unlock();
|
|
||||||
|
|
||||||
//
|
|
||||||
// dont spoof persist.sys.timezone or these other ones.
|
|
||||||
//
|
|
||||||
if (strcmp(name, "persist.sys.timezone") != 0 &&
|
|
||||||
strcmp(name, "ro.build.fingerprint") != 0 &&
|
|
||||||
strcmp(name, "ro.revision") != 0 &&
|
|
||||||
strcmp(name, "ro.build.version.sdk") != 0)
|
|
||||||
{
|
|
||||||
LOGI("spoofing hwid = %s, to = %s", value, HWID_VALUE);
|
|
||||||
value = HWID_VALUE;
|
|
||||||
}
|
|
||||||
return strlen(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ms_hook_function(int* a1, int a2, int* a3)
|
|
||||||
{
|
|
||||||
LOGI("MSHookFunction called, hooking = %p, to = %p", a1, a2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2020 xerox
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <map>
|
|
||||||
#include <atomic>
|
|
||||||
#include <memory>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
|
|
||||||
#define PAGE_START(ptr) reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(ptr) >> 12 << 12)
|
|
||||||
#define ARM_JMP_CODE 0xE51FF004
|
|
||||||
|
|
||||||
namespace shithook
|
|
||||||
{
|
|
||||||
class detour
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
detour(void* addr_to_hook, void* jmp_to, bool enable = true)
|
|
||||||
:
|
|
||||||
hook_addr(addr_to_hook),
|
|
||||||
detour_addr(jmp_to),
|
|
||||||
hook_installed(false)
|
|
||||||
{
|
|
||||||
reinterpret_cast<std::uint32_t*>(jmp_code)[0] = ARM_JMP_CODE; // LDR PC, [PC, #-4]
|
|
||||||
reinterpret_cast<void**>(jmp_code)[1] = jmp_to;
|
|
||||||
memcpy(org_bytes, hook_addr, sizeof(org_bytes));
|
|
||||||
if (enable) install();
|
|
||||||
}
|
|
||||||
|
|
||||||
void install()
|
|
||||||
{
|
|
||||||
if (hook_installed.load())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC))
|
|
||||||
{
|
|
||||||
memcpy((void*)((long)hook_addr), jmp_code, sizeof(jmp_code));
|
|
||||||
mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_EXEC);
|
|
||||||
cacheflush(reinterpret_cast<long>(hook_addr), reinterpret_cast<long>(hook_addr) + getpagesize(), NULL);
|
|
||||||
hook_installed.exchange(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void uninstall()
|
|
||||||
{
|
|
||||||
if (!hook_installed.load())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC))
|
|
||||||
{
|
|
||||||
memcpy(hook_addr, org_bytes, sizeof(jmp_code));
|
|
||||||
mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_EXEC);
|
|
||||||
cacheflush(reinterpret_cast<long>(hook_addr), reinterpret_cast<long>(hook_addr) + getpagesize(), NULL);
|
|
||||||
hook_installed.exchange(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~detour() { uninstall(); }
|
|
||||||
bool installed() { return hook_installed; }
|
|
||||||
void* hook_address() { return hook_addr; }
|
|
||||||
void* detour_address() { return detour_addr; }
|
|
||||||
private:
|
|
||||||
std::atomic<bool> hook_installed;
|
|
||||||
void* hook_addr, * detour_addr;
|
|
||||||
|
|
||||||
unsigned char jmp_code[8]{};
|
|
||||||
std::uint8_t org_bytes[sizeof(jmp_code)];
|
|
||||||
};
|
|
||||||
|
|
||||||
// this is jank, but needed because the OS isnt initalizing statics/inlined globals... :|
|
|
||||||
inline std::map<void*, std::unique_ptr<detour>>* get_hooks()
|
|
||||||
{
|
|
||||||
static std::map<void*, std::unique_ptr<detour>> hooks{};
|
|
||||||
return &hooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void make_hook(void* addr_to_hook, void* jmp_to_addr, bool enable = true)
|
|
||||||
{
|
|
||||||
if (!addr_to_hook)
|
|
||||||
return;
|
|
||||||
|
|
||||||
get_hooks()->insert({
|
|
||||||
addr_to_hook,
|
|
||||||
std::make_unique<detour>(
|
|
||||||
addr_to_hook,
|
|
||||||
jmp_to_addr,
|
|
||||||
enable
|
|
||||||
) }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void enable(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
get_hooks()->at(addr)->install();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void disable(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
get_hooks()->at(addr)->uninstall();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void remove(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
get_hooks()->erase(addr);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in new issue