现在,在我听到关于不尝试任何事情的评论之前,
有一些非常好的应用程序可以完成我想要的功能,例如NtTrace,Strace而且大致oSpy最终也可以达到相同的结果。
但是我的应用程序具有一些非常困难的反调试技术,迫使我手动执行所有操作。
这是MSDN的NdrClientCall2拒绝条件
CLIENT_CALL_RETURN RPC_VAR_ENTRY NdrClientCall2(
__in PMIDL_STUB_DESC pStubDescriptor,
__in PFORMAT_STRING pFormat,
__in_out ...
);
,因此它使用PMIDL_STUB_DESC结构,其定义如下:
typedef struct _MIDL_STUB_DESC {
void *RpcInterfaceInformation;
void* (__RPC_API *pfnAllocate)(size_t);
void (__RPC_API *pfnFree)(void*);
union {
handle_t *pAutoHandle;
handle_t *pPrimitiveHandle;
PGENERIC_BINDING_INFO pGenericBindingInfo;
} IMPLICIT_HANDLE_INFO;
const NDR_RUNDOWN *apfnNdrRundownRoutines;
const GENERIC_BINDING_ROUTINE_PAIR *aGenericBindingRoutinePairs;
const EXPR_EVAL *apfnExprEval;
const XMIT_ROUTINE_QUINTUPLE *aXmitQuintuple;
const unsigned char *pFormatTypes;
int fCheckBounds;
unsigned long Version;
MALLOC_FREE_STRUCT *pMallocFreeStruct;
long MIDLVersion;
const COMM_FAULT_OFFSETS *CommFaultOffsets;
const USER_MARSHAL_ROUTINE_QUADRUPLE *aUserMarshalQuadruple;
const NDR_NOTIFY_ROUTINE *NotifyRoutineTable;
ULONG_PTR mFlags;
const NDR_CS_ROUTINES *CsRoutineTables;
void *Reserved4;
ULONG_PTR Reserved5;
} MIDL_STUB_DESC, *PMIDL_STUB_DESC;
这就是当我放一张breakpoi时在windbg中的样子NdrClientCall2函数中的nt
0:006> .echo "Arguments:"; dds esp+4 L5
Arguments:
06d9ece4 74cc2158 SspiCli!sspirpc_StubDesc
06d9ece8 74cc2322 SspiCli!sspirpc__MIDL_ProcFormatString+0x17a
06d9ecec 06d9ed00
06d9ecf0 91640000
06d9ecf4 91640000
0:006> .echo "PMIDL_STUB_DESC:"; dds poi(esp+4) L20
PMIDL_STUB_DESC:
74cc2158 74cc2690 SspiCli!sspirpc_ServerInfo+0x24
74cc215c 74cca1cd SspiCli!MIDL_user_allocate
74cc2160 74cca1e6 SspiCli!MIDL_user_free
74cc2164 74ce0590 SspiCli!SecpCheckSignatureRoutineRefCount+0x4
74cc2168 00000000
74cc216c 00000000
74cc2170 00000000
74cc2174 00000000
74cc2178 74cc1c52 SspiCli!sspirpc__MIDL_TypeFormatString+0x2
74cc217c 00000001
74cc2180 00060001
74cc2184 00000000
74cc2188 0700022b
74cc218c 00000000
74cc2190 00000000
74cc2194 00000000
74cc2198 00000001
74cc219c 00000000
74cc21a0 00000000
74cc21a4 00000000
74cc21a8 48000000
74cc21ac 00000000
74cc21b0 001c0000
74cc21b4 00000032
74cc21b8 00780008
74cc21bc 41080646
74cc21c0 00000000
74cc21c4 000b0000
74cc21c8 00020004
74cc21cc 00080048
74cc21d0 21500008
74cc21d4 0008000c
0:006> .echo "PFORMAT_STRING:"; db poi(esp+8)
PFORMAT_STRING:
74cc2322 00 48 00 00 00 00 06 00-4c 00 30 40 00 00 00 00 .H......L.0@....
74cc2332 ec 00 bc 00 47 13 08 47-01 00 01 00 00 00 08 00 ....G..G........
74cc2342 00 00 14 01 0a 01 04 00-6e 00 58 01 08 00 08 00 ........n.X.....
74cc2352 0b 00 0c 00 20 01 0a 01-10 00 f6 00 0a 01 14 00 .... ...........
74cc2362 f6 00 48 00 18 00 08 00-48 00 1c 00 08 00 0b 00 ..H.....H.......
74cc2372 20 00 2c 01 0b 01 24 00-a2 01 0b 00 28 00 b8 01 .,...$.....(...
74cc2382 13 41 2c 00 a2 01 13 20-30 00 f8 01 13 41 34 00 .A,.... 0....A4.
74cc2392 60 01 12 41 38 00 f6 00-50 21 3c 00 08 00 12 21 `..A8...P!<....!
那么我如何确切地知道它要与之通信的远程进程是什么,或者它正在使用什么管道进行通信?
就我而言从MSDN了解到,应该调用一个远程过程。如果我理解该权利,则意味着它应该调用远程函数,就像它是导出的dll函数一样。
PS:
设置此函数的主要原因是因为NdrClientCall2似乎很大。
#1 楼
那么,我如何准确地知道它要与之通信的远程进程是什么,或者它正在使用什么管道进行通信?
第一个步骤是找到RPC客户端接口。这可以通过
NdrClientCall2()
的第一个参数pStubDescriptor
找到。在您的问题中,pStubDescriptor
指向SspiCli!sspirpc_StubDesc
:这是在windbg中的样子,当我在NdrClientCall2函数中放置断点时
/>
0:006> .echo "Arguments:"; dds esp+4 L5
Arguments:
06d9ece4 74cc2158 SspiCli!sspirpc_StubDesc
SspiCli!sspirpc_StubDesc
是MIDL_STUB_DESC
,在我的计算机上,这是其关联的值(通过IDA Pro):struct _MIDL_STUB_DESC const sspirpc_StubDesc MIDL_STUB_DESC
<
offset dword_22229B8,
offset SecClientAllocate(x),
offset MIDL_user_free(x),
<offset unk_22383F4>,
0,
0,
0,
0,
offset word_22224B2,
1,
60001h,
0,
700022Bh,
0,
0,
0,
1,
0,
0,
0
>
如MSDN上所述,上面结构中的第一个字段“指向RPC客户端接口结构”。因此,我们可以将该地址处的数据解析为一个
RPC_CLIENT_INTERFACE
结构: 我们现在可以使用RpcView查找该接口GUID,以找到相关的DLL,运行进程和端点:
以找出具体的在LSASS进程中,SSPI RPC服务器正在使用端点,我们可以反向工程
RPC_CLIENT_INTERFACE
。在导出的函数InterfaceId
中,我们看到以下调用:stru_22229B8 dd 44h ; Length
dd 4F32ADC8h ; InterfaceId.SyntaxGUID.Data1
dw 6052h ; InterfaceId.SyntaxGUID.Data2
dw 4A04h ; InterfaceId.SyntaxGUID.Data3
db 87h, 1, 29h, 3Ch, 0CFh, 20h, 96h, 0F0h; InterfaceId.SyntaxGUID.Data4
dw 1 ; InterfaceId.SyntaxVersion.MajorVersion
dw 0 ; InterfaceId.SyntaxVersion.MinorVersion
dd 8A885D04h ; TransferSyntax.SyntaxGUID.Data1
dw 1CEBh ; TransferSyntax.SyntaxGUID.Data2
dw 11C9h ; TransferSyntax.SyntaxGUID.Data3
db 9Fh, 0E8h, 8, 0, 2Bh, 10h, 48h, 60h; TransferSyntax.SyntaxGUID.Data4
dw 2 ; TransferSyntax.SyntaxVersion.MajorVersion
dw 0 ; TransferSyntax.SyntaxVersion.MinorVersion
dd offset RPC_DISPATCH_TABLE const sspirpc_DispatchTable; DispatchTable
dd 0 ; RpcProtseqEndpointCount
dd 0 ; RpcProtseqEndpoint
dd 0 ; Reserved
dd offset _MIDL_SERVER_INFO_ const sspirpc_ServerInfo; InterpreterInfo
dd 4000000h ; Flags
要弄清楚
4F32ADC8-6052-4A04-8701-293CCF2096F0
中正在调用哪个特定函数,我们需要查看传递的sspisrv.dll
数据至SspiSrvInitialize()
。在上面的示例代码中,sspisrv.dll
数据为:RpcServerUseProtseqEpW(L"ncalrpc", 0xAu, L"lsasspirpc", 0);
如果将
pFormat
数据解析为NDR_PROC_HEADER_RPC结构,则得到:00 48 00 00 00 00 06 00-4c 00 30 40 00 00 00 00 ...
从
NdrClientCall2
可以看到,此RPC调用正在调用pFormat
中的第6个RPC函数。我们可以再次使用RpcView获取第6个RPC函数的地址:使用IDA Pro,我们可以在
pFormat
的地址proc_num
处看到该函数:handle_type = 0x00
Oi_flags = 0x48
rpc_flags = 0x00000000
proc_num = 0x0006
stack_size = 0x004C
RpcView还向我们展示了该函数原型的反编译:
(请注意,在您的计算机上,第6个函数可能不在虚拟地址
sspisrv.dll
上,第六个功能可能不是sspisrv.dll
,但这仍然是您要使用的方法。)这样,我们现在可以说以下内容:
RPC
0x7573159D
调用的服务器代码在0x7573159D
中SspirProcessSecurityContext()
调用的RPC服务器在LSASS的进程中运行NdrClientCall2()
调用的端点名为sspisrv.dll
您在
NdrClientCall2()
中的NdrClientCall2()
调用所调用的RPC服务器功能是lsasspirpc
评论
好吧,这让我很想!感谢那。但是对于我的问题的第二部分,是否有办法知道什么是-final-过程?您最终发现的是导出的初始化函数,该函数调用RpcServerUseProtseqEpW(),这不是真正的函数。还是我错过了什么?
– 0xAK
2015年1月30日23:00
还是更好,我应该在哪里放置BreakPoint?
– 0xAK
15年1月30日在23:44
我已经更新了上面的答案以回答该问题。
–詹森·格夫纳(Jason Geffner)
2015年1月31日0:50
是的,这正是我想要的。仅供以后参考。.您如何确定Struct参数类型的?您怎么知道MIDL_STUB_DESC.RpcInterfaceInformation的类型是msdn只是说它指向** RPC客户端接口结构**,而我在msdn的任何地方都看不到“ RPC_CLIENT_INTERFACE”。你是在哪里找到那个东西的。顺便说一句,谢谢你的回答
– 0xAK
2015年2月1日下午6:35
我想没有什么比真实的经验。万分感谢
– 0xAK
2015年2月1日15:31