-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSysExports.h
219 lines (194 loc) · 7.13 KB
/
SysExports.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/**
* @file SysExports.h
* @brief Header file for the SysExports class, which handles the import
* and management of functions in a dynamic-link library (DLL).
* @author Kerby
* @date 2022-12-20
*/
#pragma once
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_parse_tree.hpp>
#include <boost/spirit/include/classic_attribute.hpp>
#include <boost/spirit/include/classic_push_back_actor.hpp>
#include <boost/spirit/include/classic_symbols.hpp>
#include <boost/variant.hpp>
#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <string>
using namespace boost::spirit::classic;
using namespace phoenix;
/**
* @brief A struct to store information about a single exported function.
* @var m_SerialID The serial id based on the EXE import order.
* @var m_Name The name of the function.
* @var m_dwAddress The address of the function.
* @var m_ReturnType The return type of the function.
* @var m_CallType The calling convention of the function.
* @var m_ParamTypes The types of the function's parameters.
*/
struct FunctionSpec
{
// simple variable spec
enum eVarType
{
VAR_VOID, VAR_BOOL, VAR_INT,
VAR_FLOAT, VAR_STRING, VAR_USER, VAR_UNKNOWN,
};
// possible calling conventions
enum eCallType
{
CALL_CDECL, CALL_STDCALL, CALL_THISCALL,
CALL_THISCALLVARARG, CALL_UNKNOWN
};
typedef std::vector <std::string> ParamVec;
std::vector<std::string> params; // temporary parameters vector
DWORD m_SerialID; // Serial id based on EXE import order
std::string m_Name; // Function name
DWORD m_dwAddress; // Function address
std::string m_ReturnType; // Return Type
std::string m_CallType; // Call Type
ParamVec m_ParamTypes; // Parameter type(s)
};
typedef std::vector<std::map<DWORD, FunctionSpec>>FunctionByAddrMap;
/**
* @brief A class that parses a function signature string and stores
* the resulting information in a FunctionSpec struct.
*/
class SignatureParser
{
public:
parse_info<> eParse; // flag
/*
* @brief Parses a function signature string and stores the resulting information in a FunctionSpec struct.
* @param str The function signature string to parse.
* @param spec The FunctionSpec struct to store the parsed information in.
* @return The parse_info object containing information about the success or failure of the parse operation.
*/
parse_info<> Parse(char const* str, FunctionSpec& spec)
{
symbols<> base_types, call_types, access_types;
access_types = "public:","private","protected";
base_types = "void","bool","int","char","long","short","double",
"float", "wchar_t", "char16_t", "char32_t",
"__int8", "__int16", "__int32","__int64", "long long";
call_types = "__cdecl","__stdcall","__thiscall","__fastcall";
std::string callTypeString;
std::string returnTypeString;
std::string returnTypeClass;
std::vector <std::string> paramTypes;
std::vector<std::string> v;
// Grammar rules
rule<>
rettype, datatype, calltype, params, group, function, class_name;
rule<>
rettype_signed, rettype_unsigned, rettype_class;
rule<>
top;
// Begin Grammar
top
= ( (access_types >> *space_p
>> rettype >> *space_p
>> calltype >> *space_p
>> function >> group ) |
(rettype >> *space_p
>> calltype >> *space_p
>> function >> group )
);
group
= '(' >> params >> ')';
calltype
= lexeme_d[
str_p("__")
>> *(alnum_p)][assign_a(callTypeString)
];
rettype
= ( rettype_unsigned | rettype_signed | rettype_class )[assign_a(returnTypeString)]
| eps_p[assign_a(returnTypeString, "")];
rettype_signed
= lexeme_d[
( base_types >> space_p >> ( ( str_p("const") >> space_p >> ch_p('*') ) |
( str_p("const") | ch_p('*') ) ) |
( base_types )
)
];
rettype_unsigned
= lexeme_d[
((str_p("unsigned") | str_p("virtual") | str_p("static"))
>> space_p) >> rettype_signed
];
rettype_class = lexeme_d[
(str_p("class") | str_p("struct"))
>> space_p >> class_name
][assign_a(returnTypeClass)];
/**
* This grammar will match class names such as Foo, Bar_1, and Baz::Quux_2.
* It will also match compound class names like Foo::Bar::Baz::Quux.
* It will not match class names that start with a number, such as 1Foo.
*/
class_name =
(alpha_p | ch_p('_'))
>> *(alnum_p | ch_p('_'))
>> *(str_p("::")
>> (alpha_p | ch_p('_'))
>> *(alnum_p | ch_p('_')));
/**
* This grammar will match and extract data types such as
* "int", "char*", "const char*", and "__int64", etc.
*/
datatype
= lexeme_d[
// match either "__" or any alphabetic character
(str_p("__") | alpha_p)
// match any number of characters that are either alphanumeric, a space, or an asterisk
// or match "const" followed by a space and an asterisk
>> *(alnum_p | space_p | ch_p('*') | (str_p("const") >> space_p >> ch_p('*')))
// apply the semantic action "push_back_a" to the parameter "paramTypes"
][push_back_a(paramTypes)];
function
= ( lexeme_d[
(alpha_p | ch_p('_'))
>> *(alnum_p | ch_p('_'))
>> str_p("::")
>> *((alpha_p | ch_p('_'))
>> *(alnum_p | ch_p('_'))
>> str_p("::"))
>> ((alpha_p | ch_p('_'))
>> *(alnum_p | ch_p('_')))[assign_a(spec.m_Name)]
]
);
params
= *( datatype % ch_p(',') );
parse_info<> r = parse(str,
(
top
));
spec.m_CallType = callTypeString;
// Hack to set the return type, since the `rettype` grammar rule wont spit out `rettype_class`
spec.m_ReturnType = returnTypeClass.empty() ? returnTypeString : returnTypeClass;
for (const auto& paramType : paramTypes) {
spec.m_ParamTypes.push_back(paramType);
}
return r;
}
private:
static void debug(const std::string& message)
{
std::cout << "DEBUG: " << message << std::endl;
}
};
typedef std::vector<FunctionSpec> functionVec;
class SysExports
{
public:
SysExports(void);
public:
~SysExports(void);
public:
bool ImportBindings(HMODULE module = NULL);
public:
bool ImportFunction(const char* mangledName, DWORD address, SignatureParser* parser);
functionVec m_Functions; /* temporary */
void PrintFunctionInfo();
};