|
12 | 12 | * _etext lands inside the executable segment it is bounding. |
13 | 13 | */ |
14 | 14 | static bool _pe_is_linker_boundary(const char* name) { |
| 15 | + if(!name) return false; |
| 16 | + |
15 | 17 | static const char* const BOUNDARIES[] = { |
16 | 18 | "_etext", |
17 | 19 | "_edata", |
@@ -68,66 +70,83 @@ bool pe_read_exports(RDContext* ctx, PEFormat* pe) { |
68 | 70 | } |
69 | 71 | } |
70 | 72 |
|
71 | | - for(u32 i = 0; i < exportdir.NumberOfNames; i++) { |
72 | | - RDAddress names_va, ordinals_va; |
| 73 | + RDAddress functions_va, names_va, ordinals_va; |
| 74 | + if(!pe_from_rva(pe, exportdir.AddressOfFunctions, &functions_va) || |
| 75 | + !pe_from_rva(pe, exportdir.AddressOfNames, &names_va) || |
| 76 | + !pe_from_rva(pe, exportdir.AddressOfNameOrdinals, &ordinals_va)) |
| 77 | + return false; |
73 | 78 |
|
74 | | - if(!pe_from_rva(pe, exportdir.AddressOfNames + (i * sizeof(u32)), |
75 | | - &names_va)) |
76 | | - continue; |
77 | | - if(!pe_from_rva(pe, exportdir.AddressOfNameOrdinals + (i * sizeof(u16)), |
78 | | - &ordinals_va)) |
79 | | - continue; |
| 79 | + rd_reader_seek(r, functions_va); |
80 | 80 |
|
81 | | - u32 name_rva; |
82 | | - u16 ordinal_idx; |
| 81 | + for(u32 i = 0; i < exportdir.NumberOfFunctions; i++) { |
| 82 | + u32 entry_rva; |
| 83 | + if(!rd_reader_read_le32(r, &entry_rva)) return false; |
| 84 | + if(!entry_rva) continue; |
83 | 85 |
|
84 | | - rd_reader_seek(r, names_va); |
85 | | - rd_reader_read_le32(r, &name_rva); |
86 | | - if(rd_reader_has_error(r)) continue; |
| 86 | + u32 ord = exportdir.Base + i; |
| 87 | + const char* export_name = NULL; |
87 | 88 |
|
| 89 | + rd_reader_save(r); |
88 | 90 | rd_reader_seek(r, ordinals_va); |
89 | | - rd_reader_read_le16(r, &ordinal_idx); |
90 | | - if(rd_reader_has_error(r)) continue; |
91 | | - |
92 | | - RDAddress entry_va, funcptrs_va; |
93 | | - if(!pe_from_rva( |
94 | | - pe, exportdir.AddressOfFunctions + (ordinal_idx * sizeof(u32)), |
95 | | - &funcptrs_va)) |
96 | | - continue; |
97 | | - |
98 | | - u32 funcrva; |
99 | | - rd_reader_seek(r, funcptrs_va); |
100 | | - rd_reader_read_le32(r, &funcrva); |
101 | | - if(rd_reader_has_error(r)) continue; |
102 | | - |
103 | | - bool is_fwd = |
104 | | - funcrva >= d.VirtualAddress && funcrva < d.VirtualAddress + d.Size; |
105 | | - if(is_fwd) continue; // don't handle export forwarding (yet) |
106 | | - |
107 | | - if(!pe_from_rva(pe, funcrva, &entry_va)) continue; |
108 | | - |
109 | | - RDAddress exportname_va; |
110 | | - if(!pe_from_rva(pe, name_rva, &exportname_va)) continue; |
111 | 91 |
|
112 | | - rd_reader_seek(r, exportname_va); |
113 | | - |
114 | | - usize n; |
115 | | - const char* name = rd_reader_peek_str(r, &n); |
116 | | - if(!name) continue; |
| 92 | + for(u32 j = 0; j < exportdir.NumberOfNames; j++) { |
| 93 | + u16 name_ord; |
| 94 | + |
| 95 | + if(!rd_reader_read_le16(r, &name_ord)) { |
| 96 | + rd_reader_restore(r); |
| 97 | + return false; |
| 98 | + } |
| 99 | + |
| 100 | + if((u32)name_ord == i) { |
| 101 | + u32 exportname_rva; |
| 102 | + rd_reader_seek(r, names_va + (j * sizeof(u32))); |
| 103 | + rd_reader_read_le32(r, &exportname_rva); |
| 104 | + |
| 105 | + RDAddress exportname_va; |
| 106 | + if(pe_from_rva(pe, exportname_rva, &exportname_va)) { |
| 107 | + rd_reader_seek(r, exportname_va); |
| 108 | + usize export_len = 0; |
| 109 | + export_name = rd_reader_peek_str(r, &export_len); |
| 110 | + |
| 111 | + if(export_name && export_len) { |
| 112 | + rd_library_type(ctx, exportname_va, "char", |
| 113 | + export_len + 1, RD_TYPE_NONE); |
| 114 | + } |
| 115 | + } |
| 116 | + |
| 117 | + break; |
| 118 | + } |
| 119 | + } |
117 | 120 |
|
118 | | - rd_library_type(ctx, exportname_va, "char", n + 1, RD_TYPE_NONE); |
| 121 | + RDAddress entry_va; |
| 122 | + if(pe_from_rva(pe, entry_rva, &entry_va)) { |
| 123 | + rd_set_external_ord(ctx, entry_va, NULL, ord, RD_EXT_EXPORTED); |
| 124 | + if(export_name) rd_library_name(ctx, entry_va, export_name); |
| 125 | + } |
119 | 126 |
|
120 | 127 | const RDSegment* seg = rd_find_segment(ctx, entry_va); |
121 | | - if(!seg) continue; |
122 | | - |
123 | | - if((seg->perm & RD_SP_X) && !_pe_is_linker_boundary(name)) { |
124 | | - entry_va = pe_norm(ctx, pe, entry_va); |
125 | | - rd_library_function(ctx, entry_va, name); |
| 128 | + bool is_func = seg && (seg->perm & RD_SP_X) && |
| 129 | + !_pe_is_linker_boundary(export_name); |
| 130 | + |
| 131 | + bool is_fwd = entry_rva >= d.VirtualAddress && |
| 132 | + entry_rva < d.VirtualAddress + d.Size; |
| 133 | + |
| 134 | + if(is_fwd) { |
| 135 | + // forwarded exports points to a null-terminated string |
| 136 | + // like DLLNAME.FunctionNName |
| 137 | + usize fwd_len; |
| 138 | + rd_reader_seek(r, entry_va); |
| 139 | + const char* fwd_name = rd_reader_peek_str(r, &fwd_len); |
| 140 | + |
| 141 | + if(fwd_name) { |
| 142 | + rd_library_type(ctx, entry_va, "char", fwd_len + 1, |
| 143 | + RD_TYPE_NONE); |
| 144 | + } |
126 | 145 | } |
127 | | - else |
128 | | - rd_library_name(ctx, entry_va, name); |
| 146 | + else if(is_func) |
| 147 | + rd_library_function(ctx, entry_va, NULL); |
129 | 148 |
|
130 | | - rd_set_external(ctx, entry_va, NULL, name, RD_EXT_EXPORTED); |
| 149 | + rd_reader_restore(r); |
131 | 150 | } |
132 | 151 |
|
133 | 152 | return true; |
|
0 commit comments