From 3e8520430fc55d4ddd7a4289d77f33702629e08d Mon Sep 17 00:00:00 2001 From: Hypnotika Date: Sat, 6 Jan 2024 06:42:15 +0100 Subject: [PATCH 1/4] Added IDE specific folders to gitignore. Fixed random(and wrong) return type in LM_IsProcessAlive.md Added scripts folder containing stubs.py. A stub generator bases on the API docs. --- .gitignore | 1 + bindings/python/scripts/libmem.pyi | 104 +++++++++++++++++++++++ bindings/python/scripts/stubs.py | 122 +++++++++++++++++++++++++++ docs/api/python/LM_IsProcessAlive.md | 2 +- 4 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 bindings/python/scripts/libmem.pyi create mode 100644 bindings/python/scripts/stubs.py diff --git a/.gitignore b/.gitignore index b0079e10..4d882c45 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ bindings/python/build/ bindings/python/src/libmem.* docs/examples/rust/target/ clang-format +.idea/* \ No newline at end of file diff --git a/bindings/python/scripts/libmem.pyi b/bindings/python/scripts/libmem.pyi new file mode 100644 index 00000000..f81fc9e4 --- /dev/null +++ b/bindings/python/scripts/libmem.pyi @@ -0,0 +1,104 @@ +from typing import * + + +lm_address_t = TypeVar('lm_address_t', bound=int) +lm_size_t = TypeVar('lm_size_t', bound=int) +lm_pid_t = TypeVar('lm_pid_t', bound=int) +lm_tid_t = TypeVar('lm_tid_t', bound=int) +lm_prot_t = TypeVar('lm_prot_t', bound=int) +lm_inst_t = TypeVar('lm_inst_t', bound=int) + + +LM_PATH_MAX = 260 +LM_CHARSET_UC = 1 +LM_PROT_NONE = 0 +LM_PROT_X = (1 << 0) +LM_PROT_R = (1 << 1) +LM_PROT_W = (1 << 2) +LM_PROT_XR = LM_PROT_X | LM_PROT_R +LM_PROT_XW = LM_PROT_X | LM_PROT_W +LM_PROT_RW = LM_PROT_R | LM_PROT_W +LM_PROT_XRW = LM_PROT_X | LM_PROT_R | LM_PROT_W + +class lm_module_t: + base: lm_address_t + end: lm_address_t + size: lm_size_t + path: str + name: str + +class lm_process_t: + pid: lm_pid_t + ppid: lm_pid_t + bits: lm_size_t + start_time: lm_size_t + path: str + name: str + +class lm_page_t: + base: lm_address_t + end: lm_address_t + size: lm_size_t + prot: lm_prot_t + +class lm_thread_t: + tid: lm_tid_t + +class lm_symbol_t: + addr: lm_address_t + name: str + +def LM_AllocMemory(size : int, prot : int) -> lm_address_t: ... +def LM_AllocMemoryEx(pproc : lm_process_t, size : int, prot : int) -> lm_address_t: ... +def LM_Assemble(code : str) -> lm_inst_t: ... +def LM_AssembleEx(code : str, bits : int, runtime_addr : int) -> bytearray: ... +def LM_CodeLength(code : int, minlength : int) -> int: ... +def LM_CodeLengthEx(pproc : lm_process_t, code : int, minlength : int) -> int: ... +def LM_DataScan(data : bytearray, addr : int, scansize : int) -> int: ... +def LM_DataScanEx(pproc : lm_process_t, data : bytearray, addr : int, scansize : int) -> int: ... +def LM_DemangleSymbol(symbol : str) -> str: ... +def LM_Disassemble(code : int) -> lm_inst_t: ... +def LM_DisassembleEx(code : int, bits : int, size : int, count : int, runtime_addr : int) -> lm_inst_t: ... +def LM_EnumModules() -> List[lm_module_t]: ... +def LM_EnumModulesEx(pproc : lm_process_t) -> List[lm_module_t]: ... +def LM_EnumPages() -> lm_page_t: ... +def LM_EnumProcesses() -> List[lm_process_t]: ... +def LM_EnumSymbols(pmod : lm_module_t) -> lm_symbol_t: ... +def LM_EnumSymbolsDemangled(pmod : lm_module_t) -> lm_symbol_t: ... +def LM_EnumThreads() -> List[lm_thread_t]: ... +def LM_EnumThreadsEx(pproc : lm_process_t) -> List[lm_thread_t]: ... +def LM_FindModule(name : str) -> lm_module_t: ... +def LM_FindModuleEx(pproc : lm_process_t, name : str) -> lm_module_t: ... +def LM_FindProcess(procstr : str) -> lm_process_t: ... +def LM_FindSymbolAddress(pmod : lm_module_t, name : str) -> int: ... +def LM_FindSymbolAddressDemangled(pmod : lm_module_t, name : str) -> int: ... +def LM_FreeMemory(alloc : int, size : int) -> bool: ... +def LM_FreeMemoryEx(pproc : lm_process_t, alloc : int, size : int) -> bool: ... +def LM_GetPage(addr : int) -> lm_page_t: ... +def LM_GetPageEx(pproc : lm_process_t, addr : int) -> lm_page_t: ... +def LM_GetProcess() -> lm_process_t: ... +def LM_GetProcessEx(pid : lm_pid_t) -> lm_process_t: ... +def LM_GetThread() -> lm_thread_t: ... +def LM_GetThreadEx(pproc : lm_process_t) -> lm_thread_t: ... +def LM_GetThreadProcess(pthr : lm_thread_t) -> lm_process_t: ... +def LM_HookCode(_from: int, to : int) -> int: ... +def LM_HookCodeEx(pproc : lm_process_t, _from: int, to : int) -> int: ... +def LM_IsProcessAlive(pproc : lm_process_t) -> bool: ... +def LM_LoadModule(modpath : str) -> lm_module_t: ... +def LM_LoadModuleEx(pproc : lm_process_t, modpath : str) -> lm_module_t: ... +def LM_PatternScan(pattern : bytearray, mask : str, addr : int, scansize : int) -> int: ... +def LM_PatternScanEx(pproc : lm_process_t, pattern : bytearray, mask : str, addr : int, scansize : int) -> int: ... +def LM_ProtMemory(addr : int, size : int, prot : lm_prot_t) -> lm_prot_t: ... +def LM_ProtMemoryEx(pproc : lm_process_t, addr : int, size : int, prot : lm_prot_t) -> lm_prot_t: ... +def LM_ReadMemory(src : int, size : int) -> bytearray: ... +def LM_ReadMemoryEx(pproc : lm_process_t, src : int, size : int) -> bytearray: ... +def LM_SetMemory(dst : int, byte : bytes, size : int) -> bool: ... +def LM_SetMemoryEx(pproc : lm_process_t, dst : int, byte : bytes, size : int) -> bool: ... +def LM_SigScan(sig : str, addr : int, scansize : int) -> int: ... +def LM_SigScanEx(pproc : lm_process_t, sig : str, addr : int, scansize : int) -> int: ... +def LM_UnhookCode(_from: int, trampoline : (int, int)) -> bool: ... +def LM_UnhookCodeEx(pproc : lm_process_t, _from: int, trampoline : (int, int)) -> bool: ... +def LM_UnloadModule(pmod : lm_module_t) -> bool: ... +def LM_UnloadModuleEx(pproc : lm_process_t, pmod : lm_module_t) -> bool: ... +def LM_WriteMemory(dst : int, src : bytearray) -> bool: ... +def LM_WriteMemoryEx(pproc : lm_process_t, dst : int, src : bytearray) -> bool: ... diff --git a/bindings/python/scripts/stubs.py b/bindings/python/scripts/stubs.py new file mode 100644 index 00000000..28a411ae --- /dev/null +++ b/bindings/python/scripts/stubs.py @@ -0,0 +1,122 @@ +import os +import re + +text = """from typing import * + + +lm_address_t = TypeVar('lm_address_t', bound=int) +lm_size_t = TypeVar('lm_size_t', bound=int) +lm_pid_t = TypeVar('lm_pid_t', bound=int) +lm_tid_t = TypeVar('lm_tid_t', bound=int) +lm_prot_t = TypeVar('lm_prot_t', bound=int) +lm_inst_t = TypeVar('lm_inst_t', bound=int) + + +LM_PATH_MAX = 260 +LM_CHARSET_UC = 1 +LM_PROT_NONE = 0 +LM_PROT_X = (1 << 0) +LM_PROT_R = (1 << 1) +LM_PROT_W = (1 << 2) +LM_PROT_XR = LM_PROT_X | LM_PROT_R +LM_PROT_XW = LM_PROT_X | LM_PROT_W +LM_PROT_RW = LM_PROT_R | LM_PROT_W +LM_PROT_XRW = LM_PROT_X | LM_PROT_R | LM_PROT_W + +class lm_module_t: + base: lm_address_t + end: lm_address_t + size: lm_size_t + path: str + name: str + +class lm_process_t: + pid: lm_pid_t + ppid: lm_pid_t + bits: lm_size_t + start_time: lm_size_t + path: str + name: str + +class lm_page_t: + base: lm_address_t + end: lm_address_t + size: lm_size_t + prot: lm_prot_t + +class lm_thread_t: + tid: lm_tid_t + +class lm_symbol_t: + addr: lm_address_t + name: str + +""" + +doc_path = "../../../docs/api/python" +files = os.listdir(doc_path) +files = [f for f in files if f.endswith(".md")] + + +def extract_return_types(file_name): + file_path = os.path.join(doc_path, file_name) + with open(file_path, 'r', encoding='utf-8') as file: + lines = file.readlines() + + for i, line in enumerate(lines): + if line.strip() == "# Return Value": + type_line = lines[i + 2].strip() + all_types = re.findall(r'`([^`]+)`', type_line) + extracted_types = [] + for type_str in all_types: + if ' of ' in type_str: + container, inner_type = type_str.split(' of ') + extracted_types.append(container.strip()) + extracted_types.append(inner_type.strip()) + else: + extracted_types.append(type_str.strip()) + return ', '.join(extracted_types) + + return 'Any' + + +def get_function_def(files): + function_defs = [] + for f in files: + data = open(os.path.join(doc_path, f)).readlines() + for i, line in enumerate(data): + if i == 3 and line.startswith("def"): + function_defs.append((f, line.strip())) + return function_defs + + +def write_stub(): + with open("libmem.pyi", "w") as f: + f.write(text) + for file_name, defi in get_function_def(files): + return_type = extract_return_types(file_name).split(",")[0] + if return_type == "Any" and "Module" in defi: + return_type = "List[lm_module_t]" + if return_type == "Any" and "Process" in defi: + return_type = "List[lm_process_t]" + if return_type == "Any" and "Page" in defi: + return_type = "List[lm_page_t]" + if return_type == "Any" and "Thread" in defi: + return_type = "List[lm_thread_t]" + if return_type == "Any" and "Symbol" in defi: + return_type = "List[lm_symbol_t]" + if return_type == "(trampoline_address": + return_type = "int" + if return_type == "true" or return_type == "false": + return_type = "bool" + if return_type == "": + continue + if "from :" in defi: + f.write(f"{defi.replace('from :', '_from:')} -> {return_type}: ...\n") + continue + + f.write(f"{defi} -> {return_type}: ...\n") + + +if __name__ == '__main__': + write_stub() diff --git a/docs/api/python/LM_IsProcessAlive.md b/docs/api/python/LM_IsProcessAlive.md index b50b4645..c61779ad 100644 --- a/docs/api/python/LM_IsProcessAlive.md +++ b/docs/api/python/LM_IsProcessAlive.md @@ -1,7 +1,7 @@ # LM_IsProcessAlive ```python -def LM_IsProcessAlive(pproc : lm_process_t) : bool +def LM_IsProcessAlive(pproc : lm_process_t) ``` # Description From 3fbcba1bbb2ee04b0ba21ec0859ed0565b2281be Mon Sep 17 00:00:00 2001 From: Rdbo <57117082+rdbo@users.noreply.github.com> Date: Sat, 6 Jan 2024 14:11:23 -0300 Subject: [PATCH 2/4] Update libmem.pyi --- bindings/python/scripts/libmem.pyi | 38 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/bindings/python/scripts/libmem.pyi b/bindings/python/scripts/libmem.pyi index f81fc9e4..0de20720 100644 --- a/bindings/python/scripts/libmem.pyi +++ b/bindings/python/scripts/libmem.pyi @@ -54,17 +54,17 @@ def LM_Assemble(code : str) -> lm_inst_t: ... def LM_AssembleEx(code : str, bits : int, runtime_addr : int) -> bytearray: ... def LM_CodeLength(code : int, minlength : int) -> int: ... def LM_CodeLengthEx(pproc : lm_process_t, code : int, minlength : int) -> int: ... -def LM_DataScan(data : bytearray, addr : int, scansize : int) -> int: ... -def LM_DataScanEx(pproc : lm_process_t, data : bytearray, addr : int, scansize : int) -> int: ... +def LM_DataScan(data : bytearray, addr : int, scansize : int) -> lm_address_t: ... +def LM_DataScanEx(pproc : lm_process_t, data : bytearray, addr : int, scansize : int) -> lm_address_t: ... def LM_DemangleSymbol(symbol : str) -> str: ... def LM_Disassemble(code : int) -> lm_inst_t: ... -def LM_DisassembleEx(code : int, bits : int, size : int, count : int, runtime_addr : int) -> lm_inst_t: ... +def LM_DisassembleEx(code : int, bits : int, size : int, count : int, runtime_addr : int) -> List[lm_inst_t]: ... def LM_EnumModules() -> List[lm_module_t]: ... def LM_EnumModulesEx(pproc : lm_process_t) -> List[lm_module_t]: ... -def LM_EnumPages() -> lm_page_t: ... +def LM_EnumPages() -> List[lm_page_t]: ... def LM_EnumProcesses() -> List[lm_process_t]: ... -def LM_EnumSymbols(pmod : lm_module_t) -> lm_symbol_t: ... -def LM_EnumSymbolsDemangled(pmod : lm_module_t) -> lm_symbol_t: ... +def LM_EnumSymbols(pmod : lm_module_t) -> List[lm_symbol_t]: ... +def LM_EnumSymbolsDemangled(pmod : lm_module_t) -> List[lm_symbol_t]: ... def LM_EnumThreads() -> List[lm_thread_t]: ... def LM_EnumThreadsEx(pproc : lm_process_t) -> List[lm_thread_t]: ... def LM_FindModule(name : str) -> lm_module_t: ... @@ -81,23 +81,23 @@ def LM_GetProcessEx(pid : lm_pid_t) -> lm_process_t: ... def LM_GetThread() -> lm_thread_t: ... def LM_GetThreadEx(pproc : lm_process_t) -> lm_thread_t: ... def LM_GetThreadProcess(pthr : lm_thread_t) -> lm_process_t: ... -def LM_HookCode(_from: int, to : int) -> int: ... -def LM_HookCodeEx(pproc : lm_process_t, _from: int, to : int) -> int: ... +def LM_HookCode(from: lm_address_t, to : lm_address_t) -> lm_address_t: ... +def LM_HookCodeEx(pproc : lm_process_t, from: lm_address_t, to : lm_address_t) -> lm_address_t: ... def LM_IsProcessAlive(pproc : lm_process_t) -> bool: ... def LM_LoadModule(modpath : str) -> lm_module_t: ... def LM_LoadModuleEx(pproc : lm_process_t, modpath : str) -> lm_module_t: ... -def LM_PatternScan(pattern : bytearray, mask : str, addr : int, scansize : int) -> int: ... -def LM_PatternScanEx(pproc : lm_process_t, pattern : bytearray, mask : str, addr : int, scansize : int) -> int: ... +def LM_PatternScan(pattern : bytearray, mask : str, addr : lm_address_t, scansize : int) -> lm_address_t: ... +def LM_PatternScanEx(pproc : lm_process_t, pattern : bytearray, mask : str, addr : lm_address_t, scansize : int) -> lm_address_t: ... def LM_ProtMemory(addr : int, size : int, prot : lm_prot_t) -> lm_prot_t: ... -def LM_ProtMemoryEx(pproc : lm_process_t, addr : int, size : int, prot : lm_prot_t) -> lm_prot_t: ... -def LM_ReadMemory(src : int, size : int) -> bytearray: ... -def LM_ReadMemoryEx(pproc : lm_process_t, src : int, size : int) -> bytearray: ... -def LM_SetMemory(dst : int, byte : bytes, size : int) -> bool: ... -def LM_SetMemoryEx(pproc : lm_process_t, dst : int, byte : bytes, size : int) -> bool: ... -def LM_SigScan(sig : str, addr : int, scansize : int) -> int: ... -def LM_SigScanEx(pproc : lm_process_t, sig : str, addr : int, scansize : int) -> int: ... -def LM_UnhookCode(_from: int, trampoline : (int, int)) -> bool: ... -def LM_UnhookCodeEx(pproc : lm_process_t, _from: int, trampoline : (int, int)) -> bool: ... +def LM_ProtMemoryEx(pproc : lm_process_t, addr : lm_address_t, size : int, prot : lm_prot_t) -> lm_prot_t: ... +def LM_ReadMemory(src : lm_address_t, size : int) -> bytearray: ... +def LM_ReadMemoryEx(pproc : lm_process_t, src : lm_address_t, size : int) -> bytearray: ... +def LM_SetMemory(dst : lm_address_t, byte : bytes, size : int) -> bool: ... +def LM_SetMemoryEx(pproc : lm_process_t, dst : lm_address_t, byte : bytes, size : int) -> bool: ... +def LM_SigScan(sig : str, addr : lm_address_t, scansize : int) -> lm_address_t: ... +def LM_SigScanEx(pproc : lm_process_t, sig : str, addr : lm_address_t, scansize : int) -> lm_address_t: ... +def LM_UnhookCode(from: lm_address_t, trampoline : (lm_address_t, int)) -> bool: ... +def LM_UnhookCodeEx(pproc : lm_process_t, from: lm_address_t, trampoline : (int, int)) -> bool: ... def LM_UnloadModule(pmod : lm_module_t) -> bool: ... def LM_UnloadModuleEx(pproc : lm_process_t, pmod : lm_module_t) -> bool: ... def LM_WriteMemory(dst : int, src : bytearray) -> bool: ... From fef7b0e5e827db76caf9dec086a187f28da555dc Mon Sep 17 00:00:00 2001 From: Rdbo <57117082+rdbo@users.noreply.github.com> Date: Sat, 6 Jan 2024 14:14:25 -0300 Subject: [PATCH 3/4] Update .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4d882c45..2e3bd93c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ bindings/python/build/ bindings/python/src/libmem.* docs/examples/rust/target/ clang-format -.idea/* \ No newline at end of file +.idea/ From f943f0da01557b187117ce9fbbd48221f3cc7a12 Mon Sep 17 00:00:00 2001 From: Rdbo <57117082+rdbo@users.noreply.github.com> Date: Sat, 6 Jan 2024 14:16:13 -0300 Subject: [PATCH 4/4] Update stubs.py --- bindings/python/scripts/stubs.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bindings/python/scripts/stubs.py b/bindings/python/scripts/stubs.py index 28a411ae..2602b920 100644 --- a/bindings/python/scripts/stubs.py +++ b/bindings/python/scripts/stubs.py @@ -1,3 +1,7 @@ +# TODO - New stub generation method: +# - Make the documentation declaration be exactly like how it would be on `.pyi` +# - Get the lines between the two ``` for each API in the documentation and place them directly in the `.pyi` + import os import re