Skip to content

Commit

Permalink
Merge pull request #174 from Hypnootika/master
Browse files Browse the repository at this point in the history
Feat: stub.py, a stub_generator. Fix: LM_IsProcessAlive.md
  • Loading branch information
rdbo authored Jan 6, 2024
2 parents 8ada1ac + f943f0d commit 87e2be5
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ bindings/python/build/
bindings/python/src/libmem.*
docs/examples/rust/target/
clang-format
.idea/
104 changes: 104 additions & 0 deletions bindings/python/scripts/libmem.pyi
Original file line number Diff line number Diff line change
@@ -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) -> 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) -> 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() -> List[lm_page_t]: ...
def LM_EnumProcesses() -> List[lm_process_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: ...
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: 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 : 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 : 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: ...
def LM_WriteMemoryEx(pproc : lm_process_t, dst : int, src : bytearray) -> bool: ...
126 changes: 126 additions & 0 deletions bindings/python/scripts/stubs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# 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

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()
2 changes: 1 addition & 1 deletion docs/api/python/LM_IsProcessAlive.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# LM_IsProcessAlive

```python
def LM_IsProcessAlive(pproc : lm_process_t) : bool
def LM_IsProcessAlive(pproc : lm_process_t)
```

# Description
Expand Down

0 comments on commit 87e2be5

Please sign in to comment.