apitable
Tool
tools/pe/apitable.py(program, Windows PE). Write the API table of a 32-bit Windows DLL: every export, its calling convention and the bytes of arguments it takes, read from the DLL's own code.
Run it with ./gameframe run apitable ARGS or python3 tools/pe/apitable.py. Source on GitHub.
Its own help
This is the help text in the tool itself, as ./gameframe tool apitable prints it.
text
Write the API table of a 32-bit Windows DLL: every export, its calling convention and the
bytes of arguments it takes, read from the DLL's own code.
Usage: apitable.py DLL [--header FILE ...] [--out FILE]
apitable.py IMPORT.LIB [--header FILE ...] [--out FILE]
DLL a 32-bit x86 DLL, such as a 1990s card driver library (glide2x.dll, sgl.dll)
IMPORT.LIB or the library's import library from its SDK, when the DLL is not at hand.
Its decorated names (_ATI3DCIF_Init@0) give the stdcall exports
--header F a C header of the API. Each export's prototype there gives its parameter count
and the kind of value it returns. Give several headers to search them all
--out FILE write the table there (default: standard output)
Output: a tab-separated table with a header line and one row per export, sorted by ordinal:
ordinal export symbol convention bytes params returns evidence
export the name as exported (`_grDrawTriangle@12`, `sgl_render`)
symbol the plain name (`grDrawTriangle`)
convention stdcall (the callee removes `bytes` of arguments), cdecl (the caller does),
data (the export is not code), or unknown
bytes argument bytes for stdcall, from the decorated name or the `ret N` the
function ends with; 0 for cdecl
params the parameter count from the header, or - when no header has the prototype
returns from the prototype: float (float or double, which comes back in the x87
register st0), void, int (anything else, in eax), or - without one
evidence where the convention came from: name (decorated), ret (the code), name+ret
(both agree), lib (an import library), or a note such as `ret differs: 8`
The tool follows the code of each export from its first byte with capstone. It follows both
paths of each conditional branch. It also follows direct jumps. Each `ret` found gives the
bytes the callee removes. A single value is the answer. No value leaves `unknown`: the code
ends in a jump through a pointer, or runs past 4096 instructions. Two values are reported as
a conflict. An export inside a section that is not executable is `data`.
A replacement library must export every call the original exports. Each call must remove the
same bytes from the stack. Otherwise a game that calls one the library lacks fails to load, or
crashes after the call. This table lists the calls to stub (wrappers/stubgen.py) and then to
implement.
It does not read the DLL's imports, follow calls into other functions, or say what each
argument is. Standard library, pefile and capstone. tests/run.sh checks it against a DLL
built from our own C.