amiga-bootcamp/05_reversing/dynamic/setfunction_patching.md
Ilia Sharin fca930d0db docs(amiga): make cross-references clickable markdown links
Convert bare .md path references in 29 files to proper [name](relative/path)
markdown links for GitHub navigation.
2026-04-23 12:24:21 -04:00

130 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[← Home](../../README.md) · [Reverse Engineering](../README.md)
# SetFunction — Hooking Library Vectors at Runtime
## Overview
`SetFunction()` is the official AmigaOS mechanism for **patching a library's JMP table** at runtime. It installs a custom function at a given LVO, replacing the original, and returns the old function pointer so a trampoline can be constructed.
---
## `SetFunction()` API
```c
/* exec/execbase.h */
APTR SetFunction(struct Library *library, LONG funcOffset, APTR newFunction);
/* Returns: pointer to OLD function */
```
- `library` — target library base (e.g., `DOSBase`)
- `funcOffset` — negative LVO offset (e.g., `-30` for `dos.library Open`)
- `newFunction` — your replacement function
---
## Installing a Hook
```asm
; Example: hook dos.library Write() at LVO -48
MOVEA.L _SysBase, A6
JSR (-120,A6) ; Forbid() — prevent preemption during patch
MOVEA.L _DOSBase, A1
MOVE.L #-48, A0 ; LVO for Write
LEA _my_write(PC), A2
JSR (-420,A6) ; SetFunction(DOSBase, -48, &my_write)
MOVE.L D0, _orig_write ; save original function pointer
JSR (-126,A6) ; Permit()
```
### C equivalent:
```c
static APTR orig_write;
void install_hook(void) {
Forbid();
orig_write = SetFunction((struct Library *)DOSBase, -48,
(APTR)my_write_hook);
Permit();
}
```
---
## Writing a Trampoline
The hook function must:
1. Perform its instrumentation
2. Call the original via the saved pointer
3. Return with the original return value in D0
```asm
_my_write:
; D1 = file handle, D2 = buffer, D3 = length (Write args)
MOVEM.L D0-D7/A0-A6, -(SP) ; save all (we may corrupt anything)
; ... instrumentation: log args, patch buffer, etc. ...
MOVEM.L (SP)+, D0-D7/A0-A6
MOVEA.L _orig_write, A0
JMP (A0) ; jump to original — not JSR; let original RTS
```
In C (with `__asm` constraints):
```c
LONG __asm my_write_hook(register __d1 BPTR fh,
register __d2 APTR buf,
register __d3 LONG len) {
/* instrumentation */
return ((LONG (*)(BPTR,APTR,LONG))orig_write)(fh, buf, len);
}
```
---
## Restoring on Exit
**Critical:** Always restore the original function before the program exits. Failure leaves a dangling pointer in the library JMP table, causing crashes for any subsequent users of the library.
```c
void remove_hook(void) {
Forbid();
SetFunction((struct Library *)DOSBase, -48, orig_write);
Permit();
}
/* Register with atexit: */
atexit(remove_hook);
```
---
## Thread Safety Considerations
- `Forbid()` / `Permit()` disable task switching — keep the window minimal
- If the hook itself calls OS functions, use `Disable()` / `Enable()` instead only when interrupts must be excluded
- Hooks are system-global — all tasks using the library will go through your hook
---
## Common Use Cases in RE
| Use | Hook | LVO |
|---|---|---|
| Trace file access | `dos.library Open` | 30 |
| Intercept writes | `dos.library Write` | 48 |
| Monitor memory allocation | `exec.library AllocMem` | 198 |
| Log task creation | `exec.library AddTask` | 282 |
| Spy on library opens | `exec.library OpenLibrary` | 552 |
---
## References
- NDK39: `exec/execbase.h`
- ADCD 2.1: `SetFunction` autodoc
- [live_memory_probing.md](live_memory_probing.md) — SysBase structure access
- *Amiga ROM Kernel Reference Manual: Libraries* — SetFunction chapter