概述:在 GodPotato原理分析 文中,描述了 GodPotato 的大致逻辑,但是对核心的处理操作部分没有处理,也就是——RPCSS 的接口 Hook 部分,本文就这一部分进行记录。
调试环境
前文:GodPotato原理分析
调试
代码部分我们已经了解了,那么调试部分就比较简单了,双机调试挂载目标进程,在 combase!_UseProtseq
处下断点即可。当然,整体的流程可以结合 IDA 反汇编的代码查看。
UseProtseq 函数原型
⚠️ 注意 UseProtseq
在不同版本下的参数可能不同
1 2 3 4 5 6
| __int64 __fastcall UseProtseq( void *hRpc, unsigned __int16 wTowerId, unsigned int *pdwTCPPort, tagDUALSTRINGARRAY **ppsaNewBindings, tagDUALSTRINGARRAY **ppsaSecurity)
|
触发断点
在 GodPotato 源码中,调用 unmarshalTrigger.Trigger()
就触发断点了,可以先查看下相关入参:
1 2 3
| dt /v # 或者 dx -r1 Debugger.State.Scripts.CodeFlow.Contents.host.currentThread.Stack.Frames[0]
|
主要关注参数 ppsaNewBindings
就行
代码中对 ppsaNewBindings
的使用就只有 CopyStringArray
在 call combase!CopyStringArray
处添加断点,然后看执行完成后的内容就行。单步跳过,查看写入的内容
可以看到其写入的内容由三部分,WNameEntries
、wSecurityOffset
、aStringArray
WNameEntries
: aStringArray
的长度
wSecurityOffset
:UseProtseq
的最后一个参数的长度
其中 aStringArray
的内容为 ncalrpc:[OLE9EC507FE2C47565F9B30D6BC6C29]
。而 GodPotato 则修改了这一部分逻辑,写入的 ncacn_np:localhost/pipe/GodPotato[\pipe\epmapper]
获取参数个数
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
| typedef struct { unsigned char FullPtrUsed : 1; unsigned char RpcSsAllocUsed : 1; unsigned char ObjectProc : 1; unsigned char HasRpcFlags : 1; unsigned char IgnoreObjectException : 1; unsigned char HasCommOrFault : 1; unsigned char UseNewInitRoutines : 1; unsigned char Unused : 1; } INTERPRETER_FLAGS, * PINTERPRETER_FLAGS;
typedef struct { unsigned char ServerMustSize : 1; unsigned char ClientMustSize : 1; unsigned char HasReturn : 1; unsigned char HasPipes : 1; unsigned char Unused : 1; unsigned char HasAsyncUuid : 1; unsigned char HasExtensions : 1; unsigned char HasAsyncHandle : 1; } INTERPRETER_OPT_FLAGS, * PINTERPRETER_OPT_FLAGS;
typedef struct _NDR_DCOM_OI2_PROC_HEADER { unsigned char HandleType; INTERPRETER_FLAGS OldOiFlags; unsigned short RpcFlagsLow; unsigned short RpcFlagsHi; unsigned short ProcNum; unsigned short StackSize; unsigned short ClientBufferSize; unsigned short ServerBufferSize; INTERPRETER_OPT_FLAGS Oi2Flags; unsigned char NumberParams; } NDR_DCOM_OI2_PROC_HEADER, * PNDR_DCOM_OI2_PROC_HEADER;
|
RPC结构体解析
这里我参考 GodPotato 的 C# 版本实现了 C++ 版本的解析。同时尽可能的完善了部分细节以便于学习了解相关结构体。
链接:holdyounger/DecodeRPCStruct: Decode RPC_SERVER_INTERFACE Struct,take combase.dll as an example
对于 ProcString
字段的解析参考了 rpcrt4!MulNdrpInitializeContextFromProc
函数。
对应代码的 PE 文件可以使用 https://github.com/holdyounger/DecodeRPCStruct/actions/runs/12923652850