Kaydet (Commit) 6dd601c9 authored tarafından Batuhan Taşkaya's avatar Batuhan Taşkaya

optimizations and generations about lpyhook

üst 628f53e3
lpyhook* linguist-language=C
# Created by https://www.gitignore.io/api/python
# Edit at https://www.gitignore.io/?templates=python
......@@ -181,5 +182,6 @@ modules.order
Module.symvers
Mkfile.old
dkms.conf
lpyhook.c
lpyhook.h
# End of https://www.gitignore.io/api/c
.PHONY: clean
hookify.so: hookify.c
hookify.so: hookify.c lpyhook.c
gcc `python-config --cflags` `python-config --includes` -Wl,--export-dynamic -fPIC -shared -o $@ $^ -ldl `python-config --libs`
lpyhook.c:
python gen_hook.py
clean:
rm hookify.so
rm hookify.so lpyhook.c lpyhook.h
#include <Python.h>
#include <sys/mman.h>
#pragma pack(push, 1)
static struct {
char push_rax;
char mov_rax[2];
char addr[8];
char jmp_rax[2];
}
jumper = {
.push_rax = 0x50,
.mov_rax = {0x48, 0xb8},
.jmp_rax = {0xff, 0xe0}
};
#pragma pack(pop)
#include "lpyhook.h"
#define CATLIZED_SIGN "__catlized"
#define CAPI_METHOD "exc_capi"
extern PyObject* _PyFunction_FastCallKeywords(PyObject *func, PyObject *const *stack, Py_ssize_t nargs, PyObject *kwnames);
static int unprotect_page(void* addr) {
return mprotect((char *)((size_t)addr & ~(sysconf(_SC_PAGE_SIZE) -1)), sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE | PROT_EXEC);
}
int hookifier(void* target, void* replace) {
/* Some parts based on libhook */
int count;
if(unprotect_page(replace) || unprotect_page(target)) {
return 1;
}
for(count = 0; count < 255 && ((unsigned char*)replace)[count] != 0x90; ++count);
if(count == 255) {
return 1;
}
memmove(replace+1, replace, count);
*((unsigned char *)replace) = 0x58;
memcpy(jumper.addr, &replace, sizeof (void *));
memcpy(target, &jumper, sizeof jumper);
return 0;
}
PyObject *
hookify_PyFunction_FastCallKeywords(PyObject *func, PyObject *const *stack,
Py_ssize_t nargs, PyObject *kwnames)
hookify_PyFunction_FastCallKeywords(PyObject *func, PyObject *const *stack, Py_ssize_t nargs, PyObject *kwnames)
{
__asm__("NOP");
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
......@@ -60,7 +18,7 @@ hookify_PyFunction_FastCallKeywords(PyObject *func, PyObject *const *stack,
PyObject **d;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
Py_ssize_t nd;
PyObject *w, *args, *instance, *catlizor, *meth_name, *tracked, *hooks;
PyObject *w, *args, *instance, *catlizor, *meth_name, *tracked;
int i, n, pre = 0, on_call = 0, post = 0;
assert(PyFunction_Check(func));
assert(nargs >= 0);
......@@ -144,7 +102,7 @@ static struct PyModuleDef hookify =
PyMODINIT_FUNC PyInit_hookify(void) {
__asm__("");
hookifier(_PyFunction_FastCallKeywords, &hookify_PyFunction_FastCallKeywords);
lpyhook(_PyFunction_FastCallKeywords, &hookify_PyFunction_FastCallKeywords);
return PyModule_Create(&hookify);
}
if __name__ == "__main__":
from util.libcgen import *
lpyhook = CGen("LPyHook")
hook_sign = Sign("int", "lpyhook", [Sign("void*", "t"), Sign("void*", "r")])
lpyhook.gen_header(hook_sign)
packpush_source = (
"static struct {",
f" {Sign('char', 'push_rax')};",
f" {Sign('char', 'mov_rax[2]')};",
f" {Sign('char', 'addr[8]')};",
f" {Sign('char', 'jmp_rax[2]')};",
"}",
"",
"jumper = {",
" .push_rax = 0x50,",
" .mov_rax = {0x48, 0xb8},",
" .jmp_rax = {0xff, 0xe0}",
"};",
)
source_pragmas = [
Pragma("pack", ["push", "1"], packpush_source),
Pragma("pack", ["pop"]),
]
code = textwrap.dedent(
"""
%s(%s) {
return mprotect((char *)((size_t)addr & ~(sysconf(_SC_PAGE_SIZE) -1)), sysconf(_SC_PAGE_SIZE), %s);
}
%s(%s) {
%s;
if(up(r) || up(t)) {
return 1;
}
for(count = 0; count < 255 && ((unsigned char*)r)[count] != 0x90; ++count);
if(count == 255) {
return 1;
}
memmove(r+1, r, count);
*((unsigned char *)r) = 0x58;
memcpy(jumper.addr, &r, sizeof (void *));
memcpy(t, &jumper, sizeof jumper);
return 0;
}
"""
% (
Sign("static int", "up"),
Sign("void*", "addr"),
" | ".join([f"PROT_{op.upper()}" for op in {"read", "write", "exec"}]),
Sign("int", "lpyhook"),
", ".join(map(str, [Sign("void*", "t"), Sign("void*", "r")])),
Sign("int", "count"),
)
)
lpyhook.gen_source(libs=[ "_lpyhook", "string", "unistd", "sys/mman"], pragmas=source_pragmas, source=code)
lpyhook.generate()
......@@ -2,7 +2,7 @@ from setuptools import setup, Extension
hookify = Extension(
name = 'hookify',
sources = ['hookify.c'],
sources = ['hookify.c', 'lpyhook.c'],
)
setup(
......
from __future__ import annotations
import platform
from contextlib import contextmanager
from collections import deque
from dataclasses import dataclass
from typing import Optional, List
import textwrap
@dataclass
class Sign:
typ: str
name: str
args: Optional[Sign] = None
def __str__(self):
return f"{self.typ} {self.name}"
@dataclass
class Pragma:
typ: str
args: Optional[List[str]] = None
content: Optional[str] = None
class Code(deque):
def __str__(self):
return "\n".join(self)
def write(self, *args, **kwargs):
return self.append(*args, **kwargs)
def head(self, *args, **kwargs):
return self.appendleft(*args, **kwargs)
def nl(self, fr):
if fr == "h":
self.head("")
else:
self.write("")
@contextmanager
def gcode(code_type="source", libs=None, alias=None):
code = Code()
try:
yield code
finally:
if code_type == "source":
libs = libs or []
code.nl("h")
for lib in libs:
if not lib.startswith("_"):
code.head(f"#include <{lib}.h>")
else:
code.head(f'#include "{lib[1:]}.h"')
code.nl("h")
elif code_type == "lib":
alias = alias.upper()
code.nl("h")
code.head(f"#define {alias}_H")
code.head(f"#ifndef {alias}_H")
code.nl("t")
code.write("#endif")
code.nl("t")
return code
class CGen:
CGEN_SUPPORTES = {"Linux", "Darwin"}
def __init__(self, alias):
if platform.system() not in self.CGEN_SUPPORTES:
raise OSError(f"LHook doesn't support your platform: {platform.system()}")
self.alias = alias
self.source = None
self.header = None
def generate(self):
with open(f"{self.alias.lower()}.c", "w") as source:
source.write(str(self.source))
with open(f"{self.alias.lower()}.h", "w") as header:
header.write(str(self.header))
def gen_header(self, *signs):
manager = gcode(code_type="lib", alias=self.alias)
with manager as code:
for sign in signs:
code.write(f"{sign}({', '.join(map(str, sign.args))});")
self.header = code
def gen_source(self, source, libs=None, pragmas=None):
manager = gcode(code_type="source", libs=libs, alias=self.alias)
with manager as code:
pragmas = pragmas or []
for pragma in pragmas:
code.write(f"#pragma {pragma.typ}({', '.join(pragma.args)})")
if pragma.content:
code.write("\n".join(pragma.content))
code.write(source)
self.source = code
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment