1+
2+ #include "getapi.h"
3+
4+ typedef BYTE UBYTE ;
5+
6+ typedef enum _UNWIND_OP_CODES {
7+ UWOP_PUSH_NONVOL = 0 , /* info == register number */
8+ UWOP_ALLOC_LARGE , /* no info, alloc size in next 2 slots */
9+ UWOP_ALLOC_SMALL , /* info == size of allocation / 8 - 1 */
10+ UWOP_SET_FPREG , /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
11+ UWOP_SAVE_NONVOL , /* info == register number, offset in next slot */
12+ UWOP_SAVE_NONVOL_FAR , /* info == register number, offset in next 2 slots */
13+ UWOP_SAVE_XMM128 = 8 , /* info == XMM reg number, offset in next slot */
14+ UWOP_SAVE_XMM128_FAR , /* info == XMM reg number, offset in next 2 slots */
15+ UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
16+ } UNWIND_CODE_OPS ;
17+
18+ typedef union _UNWIND_CODE {
19+ struct {
20+ UBYTE CodeOffset ;
21+ UBYTE UnwindOp : 4 ;
22+ UBYTE OpInfo : 4 ;
23+ };
24+ USHORT FrameOffset ;
25+ } UNWIND_CODE , * PUNWIND_CODE ;
26+
27+ typedef struct _UNWIND_INFO {
28+ UBYTE Version : 3 ;
29+ UBYTE Flags : 5 ;
30+ UBYTE SizeOfProlog ;
31+ UBYTE CountOfCodes ;
32+ UBYTE FrameRegister : 4 ;
33+ UBYTE FrameOffset : 4 ;
34+ UNWIND_CODE UnwindCode [1 ];
35+ } UNWIND_INFO , * PUNWIND_INFO ;
36+
37+ #define GetUnwindCodeEntry (info , index ) \
38+ ((info)->UnwindCode[index])
39+
40+ #define GetLanguageSpecificDataPtr (info ) \
41+ ((PVOID)&GetUnwindCodeEntry((info),((info)->CountOfCodes + 1) & ~1))
42+
43+ #define GetExceptionHandler (base , info ) \
44+ ((PEXCEPTION_HANDLER)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
45+
46+ #define GetChainedFunctionEntry (base , info ) \
47+ ((PRUNTIME_FUNCTION)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
48+
49+ #define GetExceptionDataPtr (info ) \
50+ ((PVOID)((PULONG)GetLanguageSpecificData(info) + 1)
51+
52+ LPVOID GetGPA (VOID ) {
53+ PPEB peb ;
54+ PPEB_LDR_DATA ldr ;
55+ PLDR_DATA_TABLE_ENTRY dte ;
56+ LPVOID addr = NULL ;
57+ BYTE c ;
58+ PIMAGE_DOS_HEADER dos ;
59+ PIMAGE_NT_HEADERS nt ;
60+ PIMAGE_DATA_DIRECTORY dir ;
61+ PIMAGE_RUNTIME_FUNCTION_ENTRY rf ;
62+ DWORD i , j , h , rva , ba ;
63+ PBYTE s1 , e1 , s2 , e2 ;
64+ PUNWIND_INFO ui ;
65+
66+ peb = (PPEB ) __readgsqword (0x60 );
67+ ldr = (PPEB_LDR_DATA )peb -> Ldr ;
68+
69+ for (dte = (PLDR_DATA_TABLE_ENTRY )ldr -> InLoadOrderModuleList .Flink ;
70+ dte -> DllBase != NULL && addr == NULL ;
71+ dte = (PLDR_DATA_TABLE_ENTRY )dte -> InLoadOrderLinks .Flink )
72+ {
73+ // is this kernelbase.dll?
74+ for (h = 0 , i = 0 ; i < dte -> BaseDllName .Length /2 ; i ++ ) {
75+ c = (BYTE )dte -> BaseDllName .Buffer [i ];
76+ h += (c | 0x20 );
77+ h = ROTR32 (h , 13 );
78+ }
79+ // if not, skip it
80+ if (h != 0x22901A8D ) continue ;
81+
82+ dos = (PIMAGE_DOS_HEADER )dte -> DllBase ;
83+ nt = RVA2VA (PIMAGE_NT_HEADERS , dte -> DllBase , dos -> e_lfanew );
84+ dir = (PIMAGE_DATA_DIRECTORY )nt -> OptionalHeader .DataDirectory ;
85+ rva = dir [IMAGE_DIRECTORY_ENTRY_EXCEPTION ].VirtualAddress ;
86+ rf = (PIMAGE_RUNTIME_FUNCTION_ENTRY ) RVA2VA (ULONG_PTR , dte -> DllBase , rva );
87+
88+ // foreach runtime function and address not found
89+ for (i = 0 ; rf [i ].BeginAddress != 0 && addr == NULL ; i ++ ) {
90+ ba = rf [i ].BeginAddress ;
91+ // we will search the code between BeginAddress and EndAddress
92+ s1 = (PBYTE )RVA2VA (ULONG_PTR , dte -> DllBase , rf [i ].BeginAddress );
93+ e1 = (PBYTE )RVA2VA (ULONG_PTR , dte -> DllBase , rf [i ].EndAddress );
94+
95+ // if chained unwind information is specified in the next entry
96+ ui = (PUNWIND_INFO )RVA2VA (ULONG_PTR , dte -> DllBase , rf [i + 1 ].UnwindData );
97+
98+ if (ui -> Flags & UNW_FLAG_CHAININFO ) {
99+ // find the last entry in the chain
100+ for (;;) {
101+ i ++ ;
102+ e1 = (PBYTE )RVA2VA (ULONG_PTR , dte -> DllBase , rf [i ].EndAddress );
103+ ui = (PUNWIND_INFO )RVA2VA (ULONG_PTR , dte -> DllBase , rf [i ].UnwindData );
104+ if (!(ui -> Flags & UNW_FLAG_CHAININFO )) break ;
105+ }
106+ }
107+ // for this address range minus the length of a near conditional jump
108+ while (s1 < (e1 - 6 )) {
109+ // is the next instruction a near conditional jump?
110+ if (s1 [0 ] == 0x0F && s1 [1 ] >= 0x80 && s1 [1 ] <= 0x8F ) {
111+ // calculate the relative virtual address of jump
112+ rva = (DWORD )(((* (DWORD * )(s1 + 2 )) + 6 + s1 ) - (PBYTE )dte -> DllBase );
113+ // try find the rva in exception list
114+ for (j = 0 ; rf [j ].BeginAddress != 0 && addr == NULL ; j ++ ) {
115+ if (rf [j ].BeginAddress == rva ) {
116+ s2 = (PBYTE )RVA2VA (ULONG_PTR , dte -> DllBase , rf [j ].BeginAddress );
117+ e2 = (PBYTE )RVA2VA (ULONG_PTR , dte -> DllBase , rf [j ].EndAddress );
118+ // try find the error code in this address range
119+ while (s2 < (e2 - 4 )) {
120+ // if this is STATUS_ORDINAL_NOT_FOUND
121+ if (* (DWORD * )s2 == 0xC0000138 ) {
122+ // calculate the virtual address of primary function
123+ addr = (PBYTE )RVA2VA (ULONG_PTR , dte -> DllBase , ba );
124+ break ;
125+ }
126+ s2 ++ ;
127+ }
128+ }
129+ }
130+ }
131+ s1 ++ ;
132+ }
133+ }
134+ }
135+ return addr ;
136+ }
137+
138+ int main (void ) {
139+ LPVOID addr = GetGPA ();
140+
141+ if (addr == NULL ) {
142+ printf ("unable to locate GetProcAddress\n" );
143+ return 0 ;
144+ }
145+
146+ printf ("GetGPA : %p\n" , addr );
147+ printf ("GetProcAddress : %p\n" ,
148+ GetProcAddress (GetModuleHandle ("kernelbase" ), "GetProcAddress" ));
149+ printf ("GetProcAddressForCaller: %p\n" ,
150+ GetProcAddress (GetModuleHandle ("kernelbase" ), "GetProcAddressForCaller" ));
151+ return 0 ;
152+ }
153+
0 commit comments