1414KNOWN_RPC_ERROR_CODE = gdef .FlagMapper (
1515 gdef .ERROR_INVALID_HANDLE ,
1616 gdef .RPC_X_BAD_STUB_DATA ,
17+ gdef .RPC_E_INVALID_HEADER ,
18+ gdef .RPC_E_DISCONNECTED ,
1719 gdef .RPC_S_UNKNOWN_IF ,
1820 gdef .RPC_S_PROTOCOL_ERROR ,
1921 gdef .RPC_S_UNSUPPORTED_TRANS_SYN ,
@@ -57,34 +59,36 @@ class ALPC_RPC_CALL(ctypes.Structure):
5759 ("UNK5" , gdef .DWORD ),
5860 ("UNK6" , gdef .DWORD ),
5961 ("UNK7" , gdef .DWORD ),
60- ("ORPC_IPID " , gdef .GUID )
62+ ("orpc_ipid " , gdef .GUID )
6163 ]
6264
6365class RPCClient (object ):
6466 """A client for RPC-over-ALPC able to bind to interface and perform calls using NDR32 marshalling"""
6567 REQUEST_IDENTIFIER = 0x11223344
68+
6669 def __init__ (self , port ):
6770 self .alpc_client = alpc .AlpcClient (port ) #: The :class:`windows.alpc.AlpcClient` used to communicate with the server
6871 self .number_of_bind_if = 0 # if -> interface
6972 self .if_bind_number = {}
7073
71- def bind (self , IID_str , version = (1 ,0 )):
72- """Bind to the ``IID_str `` with the given ``version``
74+ def bind (self , iid , version = (1 ,0 )):
75+ """Bind to the ``IID `` with the given ``version``
7376
7477 :returns: :class:`windows.generated_def.IID`
7578 """
76- IID = windows .com .IID .from_string (IID_str )
77- request = self ._forge_bind_request (IID , version , self .number_of_bind_if )
79+ if not isinstance (iid , gdef .GUID ):
80+ iid = windows .com .IID .from_string (iid )
81+ request = self ._forge_bind_request (iid , version , self .number_of_bind_if )
7882 response = self ._send_request (request )
7983 # Parse reponse
8084 request_type = self ._get_request_type (response )
8185 if request_type != gdef .RPC_RESPONSE_TYPE_BIND_OK :
8286 raise ValueError ("Unexpected reponse type. Expected RESPONSE_TYPE_BIND_OK got {0}" .format (KNOW_RESPONSE_TYPE [request_type ]))
83- iid_hash = hash (buffer (IID )[:]) # TODO: add __hash__ to IID
87+ iid_hash = hash (buffer (iid )[:]) # TODO: add __hash__ to IID
8488 self .if_bind_number [iid_hash ] = self .number_of_bind_if
8589 self .number_of_bind_if += 1
8690 #TODO: attach version information to IID
87- return IID
91+ return iid
8892
8993 def forge_alpc_request (self , IID , method_offset , params , ipid = None ):
9094 """Craft an ALPC message containing an RPC request to call ``method_offset`` of interface ``IID`
@@ -113,18 +117,17 @@ def call(self, IID, method_offset, params, ipid=None):
113117 request_type = self ._get_request_type (response )
114118 if request_type != gdef .RPC_RESPONSE_TYPE_SUCCESS :
115119 raise ValueError ("Unexpected reponse type. Expected RESPONSE_SUCCESS got {0}" .format (KNOW_RESPONSE_TYPE [request_type ]))
116-
120+ return self . _get_response_effective_data ( response )
117121 # windows.utils.sprint(ALPC_RPC_CALL.from_buffer_copy(response + "\x00" * 12))
118- data = struct .unpack ("<6I" , response [:6 * 4 ])
119- assert data [3 ] == self .REQUEST_IDENTIFIER
120- return response [4 * 6 :] # Should be the return value (not completly verified)
122+ # data = struct.unpack("<6I", response[:6 * 4])
123+ # assert data[3] == self.REQUEST_IDENTIFIER
124+ # return response[4 * 6:] # Should be the return value (not completly verified)
121125
122126 def _send_request (self , request ):
123- response = self .alpc_client .send_receive (request )
124- return response .data
127+ return self .alpc_client .send_receive (request )
125128
126129 def _forge_call_request (self , interface_nb , method_offset , params , ipid = None ):
127- # TODO: differents REQUEST_IDENTIFIER for each req ?
130+ # TODO: differents REQUEST_IDENTIFIER for each req ? Use REQUEST_IDENTIFIER to identify ORPC calls ?
128131 # TODO: what is this '0' ? (1 is also accepted) (flags ?)
129132 # request = struct.pack("<16I", gdef.RPC_REQUEST_TYPE_CALL, NOT_USED, 1, self.REQUEST_IDENTIFIER, interface_nb, method_offset, *[NOT_USED] * 10)
130133 req = ALPC_RPC_CALL ()
@@ -134,16 +137,24 @@ def _forge_call_request(self, interface_nb, method_offset, params, ipid=None):
134137 req .if_nb = interface_nb
135138 req .method_offset = method_offset
136139 if ipid :
137- req .ORPC_IPID = ipid
138- this = gdef .ORPCTHIS ()
140+ req .flags = 1 # We have a IPID
141+ req .orpc_ipid = ipid
142+ this = gdef .ORPCTHIS32 () # we use NDR32
139143 this .version = (5 ,7 )
140- this .flags = 1
141- lthis = gdef .LOCALTHIS ()
144+ this .flags = gdef .ORPCF_LOCAL
145+ # Not mandatory
146+ # this.cid = gdef.GUID.from_string("42424242-4242-4242-4242-424242424242")
147+ lthis = gdef .LOCALTHIS32 () # we use NDR32
148+ # RPC_E_INVALID_HEADER is NULL
149+ lthis .callTraceActivity = gdef .GUID .from_string ("42424242-4242-4242-4242-424242424242" )
150+ lthis .dwClientThread = windows .current_thread .tid
142151 return buffer (req )[:] + buffer (this )[:] + buffer (lthis )[:] + params
143152 return buffer (req )[:] + params
144153
145154 def _forge_call_request_in_view (self , interface_nb , method_offset , params , ipid = None ):
146155 # Version crade qui clean rien pour POC. GROS DOUTES :D
156+ if ipid :
157+ raise NotImplementedError ("RpcClient._forge_call_request_in_view() with ipid" )
147158 raw_request = self ._forge_call_request (interface_nb , method_offset , b"" )
148159 p = windows .alpc .AlpcMessage (0x2000 )
149160 section = self .alpc_client .create_port_section (0x40000 , 0 , len (params ))
@@ -171,9 +182,22 @@ def _forge_bind_request(self, uuid, syntaxversion, requested_if_nb):
171182 return buffer (req )[:]
172183
173184 def _get_request_type (self , response ):
185+ """Response is a `AlpcMessage`"""
174186 "raise if request_type == RESPONSE_TYPE_FAIL"
175- request_type = struct .unpack ("<I" , response [:4 ])[0 ]
187+ request_type = struct .unpack ("<I" , response . data [:4 ])[0 ]
176188 if request_type == gdef .RPC_RESPONSE_TYPE_FAIL :
177- error_code = struct .unpack ("<5I" , response )[2 ]
189+ error_code = struct .unpack ("<5I" , response . data )[2 ]
178190 raise ValueError ("RPC Response error {0} ({1})" .format (error_code , KNOWN_RPC_ERROR_CODE .get (error_code , error_code )))
179- return request_type
191+ return request_type
192+
193+ def _get_response_effective_data (self , response ):
194+ """Response is a `AlpcMessage` needed to handle response in message vs response in view"""
195+ if not response .view_is_valid :
196+ # Reponse directly in PORT_MESSAGE
197+ return response .data [0x18 :] # 4 * 6
198+ # Response in view M extract size from PORT_MESSAGE & read data from view
199+ assert response .port_message .u1 .s1 .TotalLength >= 0x48 # At least 0x20 of data
200+ rpcdatasize = struct .unpack ("<I" , response .data [0x18 :0x1c ])[0 ]
201+ viewattr = response .view_attribute
202+ assert viewattr .ViewSize >= rpcdatasize
203+ return windows .current_process .read_memory (viewattr .ViewBase , rpcdatasize )
0 commit comments