Working/Trying com ctypes generator

This commit is contained in:
Clement Rouault
2016-03-23 19:04:15 +01:00
parent 3cb8cc6f9e
commit 34ae5084cd
5 changed files with 419 additions and 19 deletions
+163
View File
@@ -0,0 +1,163 @@
import StringIO
from collections import namedtuple
import dummy_wintypes
import struct_parser
from winstruct import WinStruct, WinUnion, WinStructType, Ptr, WinEnum
from simpleparser import *
def initial_processing( data):
# https://gcc.gnu.org/onlinedocs/cpp/Initial-processing.html#Initial-processing
# Step 1 -> use correct end of line + add last \n if not existing
data = data.replace("\r\n", "\n")
if not data.endswith("\n"):
data = data + "\n"
# Step 2: Trigraph : fuck it
pass
# Step 3: Line merge !
data = data.replace("\\\n", "")
# Step 4 Remove comments:
ins = StringIO.StringIO(data)
outs = StringIO.StringIO()
in_str = False
res = []
while ins.tell() != len(data):
c = ins.read(1)
if ins.tell() == len(data):
outs.write(c)
break
if not in_str and c == "/":
nc = ins.read(1)
if nc == "/":
while c != "\n":
c = ins.read(1)
outs.write(c)
continue
elif nc == "*":
while c != "*" or nc != "/":
c = nc
nc = ins.read(1)
if not nc:
raise ValueError("Unmatched */")
outs.write(" ")
continue
else:
outs.write(c)
ins.seek(ins.tell() - 1)
continue
# TODO: escape in str
elif c == '"':
in_str = not in_str
outs.write(c)
outs.seek(0)
return outs.read()
class WinComParser(Parser):
PARAM_INFO = ["__RPC__deref_out", "__RPC__in", "__RPC__deref_out_opt", "__RPC__out"]
PARAM_INFO_WITH_VALUE = ["__RPC__in_ecount"]
def __init__(self, data):
data = initial_processing(data)
#print(data)
super(WinComParser, self).__init__(data)
def assert_name(self, expected_name, n=None):
if n is None:
n = self.assert_token_type(NameToken)
if n.value != expected_name:
raise ParsingError("Expected name {0} got {1} instead".format(expected_name, n.value))
return n
def parse_argument(self):
byreflevel = 0
# Pass __RPC__deref_out
while self.peek() in [NameToken(x) for x in self.PARAM_INFO + self.PARAM_INFO_WITH_VALUE]:
ign = self.assert_token_type(NameToken)
if ign.value in self.PARAM_INFO_WITH_VALUE:
# pass __RPC__in_ecount(cNames)
self.assert_token_type(OpenParenthesisToken)
while type(self.peek()) != CloseParenthesisToken:
self.next_token()
self.next_token()
type_name = self.assert_token_type(NameToken)
while type(self.peek()) == StarToken:
byreflevel += 1
discard_star = self.next_token()
arg_name = self.assert_token_type(NameToken)
if type(self.peek()) not in [CommaToken, CloseParenthesisToken]:
raise ParsingError("COM PARSING: argument decl should finish by <,> or <)> (arg {0})".format(type_name.value))
if type(self.peek()) == CommaToken:
self.assert_token_type(CommaToken)
return type_name.value, byreflevel, arg_name.value
def parse_method(self):
ret_type = self.assert_token_type(NameToken)
#print(ret_type)
self.assert_token_type(OpenParenthesisToken)
self.assert_name("STDMETHODCALLTYPE")
#if type(self.peek()) == StarToken:
self.assert_token_type(StarToken)
method_name = self.assert_token_type(NameToken)
self.assert_token_type(CloseParenthesisToken)
args = []
self.assert_token_type(OpenParenthesisToken)
while type(self.peek()) != CloseParenthesisToken:
args.append(self.parse_argument())
#print("Pass <{0}>".format(p))
self.next_token()
self.assert_token_type(ColonToken)
return ret_type.value, method_name.value, args
def parse(self):
self.assert_keyword("typedef")
self.assert_keyword("struct")
vtable_name = self.assert_token_type(NameToken).value
self.assert_token_type(OpenBracketToken)
self.assert_name("BEGIN_INTERFACE")
res = WinCOMVTABLE(vtable_name)
while self.peek() != NameToken("END_INTERFACE"):
ret_type, method_name, args = self.parse_method()
#print("Method name is {0}".format(method_name))
for arg in args:
pass
#print(" Param is {0}".format(arg))
res.add_method(ret_type, method_name, args)
end_interface = self.assert_name("END_INTERFACE")
self.assert_token_type(CloseBracketToken)
typdef = self.assert_token_type(NameToken)
self.assert_token_type(ColonToken)
return res
#print(self.data)
Method = namedtuple("Method", ["ret_type", "name", "args"])
MethodArg = namedtuple("MethodArg", ["type", "byreflevel", "name"])
class WinCOMVTABLE(object):
def __init__(self, name):
self.name = name
self.methods = []
def add_method(self, ret_type, method_name, args):
new_args = []
for type, byreflevel, name in args:
if type in ["long", "int"]:
type = type.upper()
new_args.append(MethodArg(type, byreflevel, name))
if ret_type in ["long", "int"]:
ret_type = ret_type.upper()
self.methods.append(Method(ret_type, method_name, new_args))
if __name__ == "__main__":
import sys
x = WinComParser(open(sys.argv[1]).read()).parse()
print(x)
+1 -1
View File
@@ -1 +1 @@
names = ['ATOM', 'BOOL', 'BOOLEAN', 'BYTE', 'COLORREF', 'DOUBLE', 'DWORD', 'FILETIME', 'FLOAT', 'HACCEL', 'HANDLE', 'HBITMAP', ' HBRUSH', 'HCOLORSPACE', 'HDC', 'HDESK', 'HDWP', 'HENHMETAFILE', 'HFONT', 'HGDIOBJ', 'HGLOBAL', 'HHOOK', 'HICON', 'HINSTA NCE', 'HKEY', 'HKL', 'HLOCAL', 'HMENU', 'HMETAFILE', 'HMODULE', 'HMONITOR', 'HPALETTE', 'HPEN', 'HRGN', 'HRSRC', 'HSTR', 'HTASK', 'HWINSTA', 'HWND', 'INT', 'LANGID', 'LARGE_INTEGER', 'LCID', 'LCTYPE', 'LGRPID', 'LONG', 'LPARAM', 'LPCOLESTR' , 'LPCSTR', 'LPCVOID', 'LPCWSTR', 'LPOLESTR', 'LPSTR', 'LPVOID', 'LPWSTR', 'MAX_PATH', 'MSG', 'OLESTR', 'POINT', 'POINTL ', 'RECT', 'RECTL', 'RGB', 'SC_HANDLE', 'SERVICE_STATUS_HANDLE', 'SHORT', 'SIZE', 'SIZEL', 'SMALL_RECT', 'UINT', 'ULARGE _INTEGER', 'ULONG', 'USHORT', 'VARIANT_BOOL', 'WCHAR', 'WIN32_FIND_DATAA', 'WIN32_FIND_DATAW', 'WORD', 'WPARAM', '_COORD ', '_FILETIME', '_LARGE_INTEGER', '_POINTL', '_RECTL', '_SMALL_RECT', '_ULARGE_INTEGER', 'tagMSG', 'tagPOINT', 'tagRECT' , 'tagSIZE']
names = ['HRESULT', 'ATOM', 'BOOL', 'BOOLEAN', 'BYTE', 'COLORREF', 'DOUBLE', 'DWORD', 'FILETIME', 'FLOAT', 'HACCEL', 'HANDLE', 'HBITMAP', ' HBRUSH', 'HCOLORSPACE', 'HDC', 'HDESK', 'HDWP', 'HENHMETAFILE', 'HFONT', 'HGDIOBJ', 'HGLOBAL', 'HHOOK', 'HICON', 'HINSTA NCE', 'HKEY', 'HKL', 'HLOCAL', 'HMENU', 'HMETAFILE', 'HMODULE', 'HMONITOR', 'HPALETTE', 'HPEN', 'HRGN', 'HRSRC', 'HSTR', 'HTASK', 'HWINSTA', 'HWND', 'INT', 'LANGID', 'LARGE_INTEGER', 'LCID', 'LCTYPE', 'LGRPID', 'LONG', 'LPARAM', 'LPCOLESTR' , 'LPCSTR', 'LPCVOID', 'LPCWSTR', 'LPOLESTR', 'LPSTR', 'LPVOID', 'LPWSTR', 'MAX_PATH', 'MSG', 'OLESTR', 'POINT', 'POINTL ', 'RECT', 'RECTL', 'RGB', 'SC_HANDLE', 'SERVICE_STATUS_HANDLE', 'SHORT', 'SIZE', 'SIZEL', 'SMALL_RECT', 'UINT', 'ULARGE _INTEGER', 'ULONG', 'USHORT', 'VARIANT_BOOL', 'WCHAR', 'WIN32_FIND_DATAA', 'WIN32_FIND_DATAW', 'WORD', 'WPARAM', '_COORD ', '_FILETIME', '_LARGE_INTEGER', '_POINTL', '_RECTL', '_SMALL_RECT', '_ULARGE_INTEGER', 'tagMSG', 'tagPOINT', 'tagRECT' , 'tagSIZE']
+85
View File
@@ -2,11 +2,13 @@ import sys
import os
import os.path
import re
import glob
import dummy_wintypes
import struct_parser
import func_parser
import def_parser
import com_parser
@@ -29,6 +31,8 @@ TYPE_EQUIVALENCE = [
('INT', 'c_int'),
('UCHAR', 'c_char'),
('CSHORT', 'c_short'),
('VARTYPE', 'c_ushort'),
('BSTR', 'c_wchar_p'),
('PUCHAR', 'POINTER(UCHAR)'),
('double', 'c_double'),
('FARPROC', 'PVOID'),
@@ -42,6 +46,7 @@ TYPE_EQUIVALENCE = [
('LARGE_INTEGER', 'LONGLONG'),
('PLARGE_INTEGER', 'POINTER(LARGE_INTEGER)'),
('DWORD64', 'ULONG64'),
('SCODE', 'LONG'),
('PULONG64', 'POINTER(ULONG64)'),
('PUINT', 'POINTER(UINT)'),
('PHANDLE', 'POINTER(HANDLE)'),
@@ -54,6 +59,8 @@ TYPE_EQUIVALENCE = [
('ACCESS_MASK', 'DWORD'),
('REGSAM', 'ACCESS_MASK'),
('SECURITY_CONTEXT_TRACKING_MODE', 'BOOLEAN'),
("DISPID", "LONG"),
("MEMBERID", "DISPID"),
# Will be changed at import time
('LPCONTEXT', 'PVOID'),
('HCERTSTORE', 'PVOID'),
@@ -63,13 +70,19 @@ TYPE_EQUIVALENCE = [
# For functions returning void
TYPE_EQUIVALENCE.append(('VOID', 'DWORD'))
# TRICHE
TYPE_EQUIVALENCE.append(('ITypeInfo', 'PVOID'))
known_type = dummy_wintypes.names + list([x[0] for x in TYPE_EQUIVALENCE])
known_type += ["void"]
FUNC_FILE = "winfunc.txt"
STRUCT_FILE = "winstruct.txt"
DEF_FILE = "windef.txt"
NTSTATUS_FILE = "ntstatus.txt"
COM_INTERFACE_DIR_GLOB = "com/*.txt"
GENERATED_STRUCT_FILE = "winstructs"
GENERATED_FUNC_FILE = "winfuncs"
@@ -108,6 +121,32 @@ def verif_funcs_type(funcs, structs, enums):
if param_type not in known_type and param_type not in all_struct_name:
raise ValueError("UNKNOW PARAM TYPE {0}".format(param_type))
def verif_com_interface_type(vtbls, struc, enum):
all_struct_name = get_all_struct_name(structs, enums)
all_interface_name = []
#ALSO accept void
for vtbl in vtbls:
if not vtbl.name.endswith("Vtbl"):
raise ValueError("Com interface are expected to finish by <Vtbl> got <{0}".format(vtbl.name))
all_interface_name.append(vtbl.name.rstrip("Vtbl"))
for vtbl in vtbls:
#print(vtbl)
for method in vtbl.methods:
#print("Checking ret type <{0}>".format(method.ret_type))
ret_type = method.ret_type
if ret_type not in known_type and ret_type not in all_struct_name + all_interface_name:
raise ValueError("UNKNOW RET TYPE {0}".format(ret_type))
for arg in method.args:
#print("Checking arg type <{0}>".format(arg.type))
param_type = arg.type
if param_type not in known_type and param_type not in all_struct_name + all_interface_name:
#if param_type != "ITypeInfo":
raise ValueError("UNKNOW PARAM TYPE {0}".format(param_type))
def check_in_define(name, defs):
return any(name == d.name for d in defs)
@@ -200,12 +239,51 @@ def generate_struct_ctypes(structs, enums):
return ctypes_str
com_interface_header = """
from windows.simple_com import *
import ctypes
"""
com_interface_template = """
class {0}(COMInterface):
_functions_ = {{
{1}
}}
"""
com_interface_method_template = """ "{0}": ctypes.WINFUNCTYPE({1}),"""
def generate_com_interface_ctype(vtbls):
print(vtbls)
define = []
for vtbl in vtbls:
methods_string = []
for method in vtbl.methods:
args_to_define = method.args[1:] #ctypes doesnt not need the This
#import pdb;pdb.set_trace()
methods_string.append(com_interface_method_template.format(method.name, ", ".join([method.ret_type] + [arg.type for arg in args_to_define])))
#import pdb;pdb.set_trace()
define.append((com_interface_template.format(vtbl.name, "\n".join(methods_string))))
return "\n".join(define)
def write_to_out_file(name, data):
for out_dir in OUT_DIRS:
f = open("{0}/{1}.py".format(out_dir, name), 'w')
f.write(data)
f.close()
def parse_com_interfaces(filenames):
res = []
for filename in filenames:
print("Parsing COM from <{0}>".format(filename))
data = open(filename).read()
vtbl = com_parser.WinComParser(data).parse()
res.append(vtbl)
return res
def_code = open(DEF_FILE, 'r').read()
funcs_code = open(FUNC_FILE, 'r').read()
structs_code = open(STRUCT_FILE, 'r').read()
@@ -214,9 +292,11 @@ defs = def_parser.WinDefParser(def_code).parse()
funcs = func_parser.WinFuncParser(funcs_code).parse()
structs, enums = struct_parser.WinStructParser(structs_code).parse()
vtbls = parse_com_interfaces(glob.glob(COM_INTERFACE_DIR_GLOB))
validate_structs(structs, enums, defs)
verif_funcs_type(funcs, structs, enums)
verif_com_interface_type(vtbls, structs, enums)
# Create Flags for ntstatus
@@ -229,6 +309,11 @@ defs = nt_status_defs + defs
defs_ctypes = generate_defs_ctypes(defs)
funcs_ctypes = generate_funcs_ctypes(funcs)
structs_ctypes = generate_struct_ctypes(structs, enums)
com_interface_ctypes = generate_com_interface_ctype(vtbls)
f = open("yolo.py", "w")
f.write(com_interface_ctypes)
f.close()
for out_dir in OUT_DIRS:
if not os.path.exists(out_dir):
+23 -16
View File
@@ -14,7 +14,7 @@ class WinStructParser(Parser):
def parse_def(self):
if self.peek() == KeywordToken("struct"):
discard = self.next_token()
def_type_tok = self.assert_token_type(NameToken)
def_type = WinStructType(def_type_tok.value)
if type(self.peek()) == StarToken:
@@ -26,7 +26,7 @@ class WinStructParser(Parser):
if type(self.peek()) == ColonToken:
self.next_token()
return (def_type, def_name, 1)
number_rep = self.parse_array()
self.assert_token_type(ColonToken)
return (def_type, def_name, number_rep)
@@ -65,7 +65,7 @@ class WinStructParser(Parser):
else:
if assigned_value:
raise ParsingError("Enum {0} mix def with and without equal".format(enum_name))
res_enum.add_enum_entry(i, name.value)
if not type(self.peek()) == CloseBracketToken:
self.assert_token_type(CommaToken)
@@ -75,13 +75,17 @@ class WinStructParser(Parser):
#other_name = self.assert_token_type(NameToken).value
#res_enum.add_typedef(other_name)
#self.assert_token_type(ColonToken)
return res_enum
return res_enum
def parse_winstruct(self):
self.assert_keyword("typedef")
is_typedef = False
peeked = self.peek()
if peeked == KeywordToken("typedef"):
self.assert_keyword("typedef")
is_typedef = True
def_type = self.assert_token_type(KeywordToken)
if def_type.value == "enum":
return self.parse_enum()
@@ -93,14 +97,17 @@ class WinStructParser(Parser):
raise ParsingError("Expecting union or struct got <{0}> instead".format(def_type.value))
struct_name = self.assert_token_type(NameToken)
self.assert_token_type(OpenBracketToken)
result = WinDefType(struct_name.value)
while type(self.peek()) != CloseBracketToken:
tok_type, tok_name, nb_rep = self.parse_def()
result.add_field((tok_type, tok_name.value, nb_rep))
self.assert_token_type(CloseBracketToken)
self.parse_typedef(result)
if is_typedef:
self.parse_typedef(result)
else:
self.assert_token_type(ColonToken)
return result
def parse(self):
@@ -115,7 +122,7 @@ class WinStructParser(Parser):
else:
raise ValueError("Unknow returned type {0}".format(x))
return strucs, enums
def dbg_lexer(data):
for i in Lexer(data).token_generation():
print i
@@ -125,9 +132,9 @@ def dbg_parser(data):
def dbg_validate(data):
return validate_structs(Parser(data).parse())
if __name__ == "__main__":
import sys
data = open(sys.argv[1], 'r').read()
ctypes_code = generate_ctypes(data)
#data = open(sys.argv[1], 'r').read()
#ctypes_code = generate_ctypes(data)
+147 -2
View File
@@ -363,6 +363,31 @@ typedef enum _SID_NAME_USE {
SidTypeLabel = 10
} SID_NAME_USE, *PSID_NAME_USE;
typedef enum NET_FW_PROFILE_TYPE2_ {
NET_FW_PROFILE2_DOMAIN = 0x1,
NET_FW_PROFILE2_PRIVATE = 0x2,
NET_FW_PROFILE2_PUBLIC = 0x4,
NET_FW_PROFILE2_ALL = 0x7fffffff
} NET_FW_PROFILE_TYPE2;
typedef enum NET_FW_ACTION_ {
NET_FW_ACTION_BLOCK = 0,
NET_FW_ACTION_ALLOW = 1,
NET_FW_ACTION_MAX = 2
} NET_FW_ACTION;
typedef enum NET_FW_MODIFY_STATE_ {
NET_FW_MODIFY_STATE_OK = 0,
NET_FW_MODIFY_STATE_GP_OVERRIDE = 1 ,
NET_FW_MODIFY_STATE_INBOUND_BLOCKED = 2
} NET_FW_MODIFY_STATE;
typedef enum NET_FW_RULE_DIRECTION_ {
NET_FW_RULE_DIR_IN = 1,
NET_FW_RULE_DIR_OUT = 2 ,
NET_FW_RULE_DIR_MAX = 3
} NET_FW_RULE_DIRECTION;
typedef struct _LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
@@ -1278,7 +1303,126 @@ typedef struct _GUID {
USHORT Data2;
USHORT Data3;
UCHAR Data4[ 8 ];
} GUID;
} GUID, IID, *REFIID;
struct _TMP_signscale {
BYTE scale;
BYTE sign;
};
struct _TMP_lowmid {
ULONG Lo32;
ULONG Mid32;
};
union TMP_signscale_union {
_TMP_signscale s;
USHORT signscale;
};
union TMP_lowmid_union {
_TMP_lowmid s;
ULONGLONG Lo64;
};
typedef struct tagDEC {
USHORT wReserved;
TMP_signscale_union u1;
ULONG Hi32;
TMP_signscale_union u2;
} DECIMAL;
typedef struct __tagBRECORD {
PVOID pvRecord;
PVOID pRecInfo;
} _tagBRECORD;
union TMP_variant_sub_union{
LONGLONG llVal;
LONG lVal;
BYTE bVal;
SHORT iVal;
FLOAT fltVal;
DOUBLE dblVal;
VARIANT_BOOL boolVal;
SCODE scode;
BSTR bstrVal;
PVOID punkVal;
PVOID pdispVal;
SAFEARRAY *parray;
BYTE *pbVal;
SHORT *piVal;
LONG *plVal;
LONGLONG *pllVal;
FLOAT *pfltVal;
DOUBLE *pdblVal;
VARIANT_BOOL *pboolVal;
SCODE *pscode;
BSTR *pbstrVal;
PVOID byref;
CHAR cVal;
USHORT uiVal;
ULONG ulVal;
ULONGLONG ullVal;
INT intVal;
UINT uintVal;
CHAR *pcVal;
USHORT *puiVal;
ULONG *pulVal;
ULONGLONG *pullVal;
INT *pintVal;
UINT *puintVal;
_tagBRECORD __VARIANT_NAME_4;
};
typedef enum tagTYPEKIND {
TKIND_ENUM = 0,
TKIND_RECORD = 1 ,
TKIND_MODULE = 2 ,
TKIND_INTERFACE = 3 ,
TKIND_DISPATCH = 4 ,
TKIND_COCLASS = 5 ,
TKIND_ALIAS = 6 ,
TKIND_UNION = 7 ,
TKIND_MAX = 8
} TYPEKIND;
typedef struct __tagVARIANT {
VARTYPE vt;
WORD wReserved1;
WORD wReserved2;
WORD wReserved3;
TMP_variant_sub_union __VARIANT_NAME_3;
} _tagVARIANT, VARIANT, VARIANTARG, *LPVARIANT, *LPVARIANTARG;
typedef struct tagDISPPARAMS {
VARIANTARG *rgvarg;
DISPID *rgdispidNamedArgs;
UINT cArgs;
UINT cNamedArgs;
} DISPPARAMS;
typedef struct tagEXCEPINFO {
WORD wCode;
WORD wReserved;
BSTR bstrSource;
BSTR bstrDescription;
BSTR bstrHelpFile;
DWORD dwHelpContext;
ULONG_PTR pvReserved;
ULONG_PTR pfnDeferredFillIn;
SCODE scode;
} EXCEPINFO;
typedef struct _CRYPTOAPI_BLOB {
DWORD cbData;
@@ -1797,4 +1941,5 @@ typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION {
DWORD UserSidOffset;
DWORD DataLength;
DWORD DataOffset;
} EVENTLOGRECORD, *PEVENTLOGRECORD;
} EVENTLOGRECORD, *PEVENTLOGRECORD;