Skip to content

Commit 99fe0bb

Browse files
committed
Update the documentation
Closes #62 Closes #40
1 parent b22e8e3 commit 99fe0bb

File tree

1 file changed

+88
-3
lines changed

1 file changed

+88
-3
lines changed

README.md

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,13 @@ The `quiet` flag suppresses the logs about DLLs loaded and memory regions set up
8383

8484
### Custom syscall implementation
8585

86-
**Note**: This part of dumpulator still needs a lot of work.
86+
You can (re)implement syscalls by using the `@syscall` decorator:
8787

8888
```python
89-
from dumpulator import Dumpulator, syscall
89+
from dumpulator import *
9090
from dumpulator.native import *
91+
from dumpulator.handles import *
92+
from dumpulator.memory import *
9193

9294
@syscall
9395
def ZwQueryVolumeInformationFile(dp: Dumpulator,
@@ -100,7 +102,90 @@ def ZwQueryVolumeInformationFile(dp: Dumpulator,
100102
return STATUS_NOT_IMPLEMENTED
101103
```
102104

103-
You can get the syscall parameters from [ntsyscalls.py](https://github.com/mrexodia/dumpulator/blob/main/src/dumpulator/ntsyscalls.py). There are also a lot of examples there on how to use the API.
105+
All the syscall function prototypes can be found in [ntsyscalls.py](https://github.com/mrexodia/dumpulator/blob/main/src/dumpulator/ntsyscalls.py). There are also a lot of examples there on how to use the API.
106+
107+
To hook an existing syscall implementation you can do the following:
108+
109+
```python
110+
import dumpulator.ntsyscalls as ntsyscalls
111+
112+
@syscall
113+
def ZwOpenProcess(dp: Dumpulator,
114+
ProcessHandle: Annotated[P[HANDLE], SAL("_Out_")],
115+
DesiredAccess: Annotated[ACCESS_MASK, SAL("_In_")],
116+
ObjectAttributes: Annotated[P[OBJECT_ATTRIBUTES], SAL("_In_")],
117+
ClientId: Annotated[P[CLIENT_ID], SAL("_In_opt_")]
118+
):
119+
process_id = ClientId.read_ptr()
120+
assert process_id == dp.parent_process_id
121+
ProcessHandle.write_ptr(0x1337)
122+
return STATUS_SUCCESS
123+
124+
@syscall
125+
def ZwQueryInformationProcess(dp: Dumpulator,
126+
ProcessHandle: Annotated[HANDLE, SAL("_In_")],
127+
ProcessInformationClass: Annotated[PROCESSINFOCLASS, SAL("_In_")],
128+
ProcessInformation: Annotated[PVOID, SAL("_Out_writes_bytes_(ProcessInformationLength)")],
129+
ProcessInformationLength: Annotated[ULONG, SAL("_In_")],
130+
ReturnLength: Annotated[P[ULONG], SAL("_Out_opt_")]
131+
):
132+
if ProcessInformationClass == PROCESSINFOCLASS.ProcessImageFileNameWin32:
133+
if ProcessHandle == dp.NtCurrentProcess():
134+
main_module = dp.modules[dp.modules.main]
135+
image_path = main_module.path
136+
elif ProcessHandle == 0x1337:
137+
image_path = R"C:\Windows\explorer.exe"
138+
else:
139+
raise NotImplementedError()
140+
buffer = UNICODE_STRING.create_buffer(image_path, ProcessInformation)
141+
assert ProcessInformationLength >= len(buffer)
142+
if ReturnLength.ptr:
143+
dp.write_ulong(ReturnLength.ptr, len(buffer))
144+
ProcessInformation.write(buffer)
145+
return STATUS_SUCCESS
146+
return ntsyscalls.ZwQueryInformationProcess(dp,
147+
ProcessHandle,
148+
ProcessInformationClass,
149+
ProcessInformation,
150+
ProcessInformationLength,
151+
ReturnLength
152+
)
153+
```
154+
155+
### Custom structures
156+
157+
Since `v0.2.0` there is support for easily declaring your own structures:
158+
159+
```python
160+
from dumpulator.native import *
161+
162+
class PROCESS_BASIC_INFORMATION(Struct):
163+
ExitStatus: ULONG
164+
PebBaseAddress: PVOID
165+
AffinityMask: KAFFINITY
166+
BasePriority: KPRIORITY
167+
UniqueProcessId: ULONG_PTR
168+
InheritedFromUniqueProcessId: ULONG_PTR
169+
```
170+
171+
To instantiate these structures you have to use a `Dumpulator` instance:
172+
173+
```python
174+
pbi = PROCESS_BASIC_INFORMATION(dp)
175+
assert ProcessInformationLength == Struct.sizeof(pbi)
176+
pbi.ExitStatus = 259 # STILL_ACTIVE
177+
pbi.PebBaseAddress = dp.peb
178+
pbi.AffinityMask = 0xFFFF
179+
pbi.BasePriority = 8
180+
pbi.UniqueProcessId = dp.process_id
181+
pbi.InheritedFromUniqueProcessId = dp.parent_process_id
182+
ProcessInformation.write(bytes(pbi))
183+
if ReturnLength.ptr:
184+
dp.write_ulong(ReturnLength.ptr, Struct.sizeof(pbi))
185+
return STATUS_SUCCESS
186+
```
187+
188+
If you pass a pointer value as a second argument the structure will be read from memory. You can declare pointers with `myptr: P[MY_STRUCT]` and dereferences them with `myptr[0]`.
104189

105190
## Collecting the dump
106191

0 commit comments

Comments
 (0)