http://andylin02.iteye.com/blog/457411 win32 rpc编程系列四篇 已看
http://www.ibm.com/developerworks/cn/aix/library/au-rpc_programming/ rpc编程 已看
sudami的sandbox代码
http://bbs.pediy.com/showthread.php?t=172274&highlight=rpc
http://www.hsc.fr/ressources/articles/win_net_srv/index.html
http://bbs.pediy.com/showthread.php?t=77899&highlight=rpc
http://msdn.microsoft.com/en-us/library/cc213372.aspx
http://bbs.pediy.com/showthread.php?t=79437&highlight=rpc
http://bbs.pediy.com/showthread.php?t=140154
RPC/XDR/NFS系列 文章
LPC:连接端口(服务进程),通信端口。大于256字节,报文是共享内存。小于则是报文发送。
csrss,lsass->lpc.跨进程的过程调用。port是进程间通信机制,lpc是建立在这上面的应用。
NtCreatePort
NtCreateWaitablePort()
NtListenPort()
NtConnectPort()
NtAcceptConnectPort()
NtCompleteConnectPort()
NtRequestPort()
NtRequestWaiReplyPort()
NtReplyPort()
NtReplyWaitReceivePort()
NtReplyWaitReceivePortEx()。同上,但是带有超时控制
NtReadRequestData()
NtWriteRequestData()
NtQueryInformationPort()
客户 服务端
NtCreatePort(端口服务线程)
NtListenPort->NtReplyWaitReceivePort(无线for 循环,如果是应答报文,EiReplyOrRequestPort发送应答报文(EiEnqueueMessagePort()发送操作只是挂入目标端口的接收
报文队列,拷贝数据时,只是拷贝报文本身,通过共享内存共享数据部分),如果是连接请求报文,EiEnqueueConnectMessagePort()把它挂入端口的ConnectQueueListHead队列(缓存连接请求),这是为随后的“接受连接”操作、即系
统调用NtAcceptConnectPort()留下一个参考).
NtConnectPort目标是一个连接端口(EiConnectPort(ObCreateObject,EiReplyOrRequestPort(把报文的容器挂入目标连接端口的接收队列),KeReleaseSemaphore(唤醒服务线程))
把数据存入LPC_SECTION_WRITE/READ中
NtAcceptConnectPort创建无名通信端口,返回handle(如果是拒绝,EiReplyOrRequestPort在对方端口挂个拒绝报文。)
NtCompleteConnectPort唤醒客户线程
EiDequeueMessagePort()从通讯端口队列中获取对方应答报文。
创建线程(LPC服务线程),提供LPC服务。从通信端口接受报文,等待客户端服务请求而阻塞。
NtListenPort等待新连接
NtRequestPort(不等回复),NtRequestWaitReplyPort(等待回复)发送报文,请求LPC服务而阻塞 服务端接受报文提供服务,NtReplyPort回答报文,客户端解除阻塞。
eport中有信号量,实现通信双方同步。
三种报文,两种特殊,一种数据。特殊:连接请求,连接应答。在报文的data部分。
com:
1. 杨老的com教程
2. com原理与应用
com实现-潘爱民
com原理与应用
com本质论
com技术内幕 64页
ole2对象链接与嵌入技术高级编程技术
http://blog.chinaunix.net/uid-20071539-id-1978405.html com实现过程。
进程外的COM以及DCOM,前者是基于LPC 本地过程调用,后者是基于RPC远程过程调用。除了协议不同外,其他的都一样。
exports
DllGetClassObject, 返回类工厂接口。
DllCanUnloadNow, 告诉客户端该COM是否可以被正常卸载。
DllRegisterServer, 向系统注册COM组件信息。Regsvr32.exe 就是调用这个函数来进行注册的。
DllUnregisterServer 从系统中反注册一个COM。Regsvr32.exe 就是调用这个函数来进行反注册的。
1. CreateCOMObject -- CoCreateInstance。 CoCreateInstance 在注册表中查找COM的注册信息。
2. CoCreateInstance - CoGetClassObject 。注册信息被交给CoGetClassObject。这时候CoGetClassObject将知道COM组件在磁盘上的位置。
3.CoGetClassObject - LoadLibrary 。LoadLibrary 将寻找COM DLL的入口,然后GetProcAddress调用其输出函数DllGetClassObject
4. DllGetClassObject 的输出参数将向我们返回“类工厂”接口IClassFactory。
5. IclassFactory -- CreateInstance 。CreateInstance方法建立其我们实现接口的类。该类将调用自身的QueryInterface 方法,查看用户指定的接口是否被自己实现,如果实现了,则向返回自定义的接口。
6. 调用结束后,COM客户将调用COM的DLL输出函数DllCanUnloadNow 。如果该函数返回S_OK,则释放该组件。
CLASS_xx 类型的GUID,是用来标识COM组件的。
IID_xx类型的GUID,是用来标识一个接口的。可以有多个。
LIBID_xx类型的GUID,是用来标识一个TypeLib的。
AddRef 方法:
该方法用于增加一个COM的计数器。我们知道COM Server是需要支持多客户调用的,在COM中每实现一次调用,就必须进行计数。如果COM的计数>0 ,则COM继续生存。否则,该COM接口实例就必须被注销。
_Release 方法:
该方法和_AddRef方法相反,用于减少一个计数,当计数为0,则注销该接口。
QueryInterface 方法:
该方法用于查询一个接口是否存在,如果存在则在输出参数里返回该接口指针。
ProgID:程序标志,由项目名称和类名两部分组成。如: project.class1
LocalServer32:进程外组件,如ActiveX EXE这样的进程外服务器中的组件需要该子键
该子键保存了服务器文件的物理路径。
InprocServer32:进程内组件,如ActiveX DLL这样的进程内服务器中的组件需要该子键
该子键保存了服务器文件的物理路径。
TypeLib:类型库。它所对应的数据在HKEY_CLASSES_ROOT\TypeLib下面互相联系。
Vb的工程->引用对话框,就是通过该键来填充列表的。
typedef struct _PORT_MESSAGE
{
union
{
struct
{
CSHORT DataLength; //数据部分大小
CSHORT TotalLength;
} s1;
ULONG Length;
} u1;
union
{
struct
{
CSHORT Type;
CSHORT DataInfoOffset;
} s2;
ULONG ZeroInit;
} u2;
union
{
CLIENT_ID ClientId; //内含本进程和线程的句柄
QUAD DoNotUseThisField;
};
ULONG MessageId; //报文序号,每次递增
union
{
SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages
ULONG CallbackId; // only valid for LPC_REQUEST messages
}; //后面数据部分就开始了,通信双方协定
} PORT_MESSAGE, *PPORT_MESSAGE;
修改密码:
目标端口是\\LsaAuthenticationPort,
netapi32!netuserchangepassword->secur32!lsacallauthenticationpackage->ntdll!ntrequestwaitreplyport
kd> dd 0012f718 //sendmessage
0012f718 00a80020 00000000 ffffffff 7c937de9
0012f728 7c937ea0 77fc0000 00000002 00000000 //00000002之前是PORT_MESSAGE,占6个ulong,24个字节
0012f738 00000006 0015f7c8 00000068 7c80ae6e //下面0015f7c8是第10个ulong,
0012f748 0012f768 7c80ae80 77fc0000 00000000
0012f758 00000002 5fe1b580 001d001c 5fe1be88
kd> dd 0015f7c8+c //指向unicode的指针
0015f7d4 001c001a 0015f810 00027f00 0015f82c //0015f810指向用户名
end task 下断 nt!NtReplyPort,Bprotect!IsProtectLpcRequest+0x8c,看nt4源码中的 CSRSRV!CsrApiRequestThread
typedef struct _PORT_MESSAGE
{
USHORTDataSize;
USHORTMessageSize;
USHORTMessageType;
USHORTVirtualRangesOffset;
CLIENT_IDClientId;
ULONGMessageId;
ULONGSectionSize;
//UCHARData[];
} PORT_MESSAGE, *PPORT_MESSAGE;
typedef struct _CSR_CAPTURE_HEADER {
ULONG Length;
struct _CSR_CAPTURE_HEADER *RelatedCaptureBuffer;
ULONG CountMessagePointers;
PCHAR FreeSpace;
ULONG_PTR MessagePointerOffsets[1]; // Offsets within CSR_API_MSG of pointers
} CSR_CAPTURE_HEADER, *PCSR_CAPTURE_HEADER;
typedef ULONG CSR_API_NUMBER;
typedef struct _BASE_CREATETHREAD_MSG
{
HANDLE hThread;
CLIENT_ID ClientId;
}BASE_CREATETHREAD_MSG, *PBASE_CREATETHREAD_MSG;
typedef struct _PBASE_CREATEPROCESS_MSG
{
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
DWORD CreationFlags;
CLIENT_ID DebuggerClientId;
DWORD VdmBinaryType;
}BASE_CREATEPROCESS_MSG ,*PBASE_CREATEPROCESS_MSG;
typedef struct _BASE_API_MSG
{
PORT_MESSAGE PortMessage;
PCSR_CAPTURE_HEADER CaptureBuffer;
CSR_API_NUMBER ApiNumber;
ULONG Status;
ULONG Reserved;
union
{
BASE_CREATETHREAD_MSG BaseCreateThread;
BASE_CREATEPROCESS_MSG BaseCreateProcess;
}u;
}BASE_API_MSG,*PBASE_API_MSG;
typedef struct _CSR_API_CONNECTINFO
{
OUT HANDLE ObjectDirectory;
OUT PVOID SharedSectionBase;
OUT PVOID SharedStaticServerData;
OUT PVOID SharedSectionHeap;
OUT ULONG DebugFlags;
OUT ULONG SizeOfPebData;
OUT ULONG SizeOfTebData;
OUT ULONG NumberOfServerDllNames;
OUT HANDLE ServerProcessId;
} CSR_API_CONNECTINFO, *PCSR_API_CONNECTINFO;
typedef struct _CSR_CLIENTCONNECT_MSG
{
IN ULONG ServerDllIndex;
IN OUT PVOID ConnectionInformation;
IN OUT ULONG ConnectionInformationLength;
} CSR_CLIENTCONNECT_MSG, *PCSR_CLIENTCONNECT_MSG;
typedef struct _CSR_API_MSG
{
PORT_MESSAGE h; //24个字节
union
{
CSR_API_CONNECTINFO ConnectionRequest;
struct
{
PCSR_CAPTURE_HEADER CaptureBuffer;
CSR_API_NUMBER ApiNumber; //第28个字节
ULONG ReturnValue; //32
ULONG Reserved; //36
union
{
CSR_CLIENTCONNECT_MSG ClientConnect;
ULONG_PTR ApiMessageData[39]; //40 ,end task 的窗口句柄是第44个.
} u;
};
};
} CSR_API_MSG, *PCSR_API_MSG; --------->end task时的消息结构
服务service.exe向svchost通信的rpc msg头部
typedef struct _CTRL_MSG_HEADER {
DWORD Count; // num bytes in buffer.
DWORD OpCode; // control opcode.
DWORD NumCmdArgs; // number of command Args.
参数个数
SERVICE_STATUS_HANDLE StatusHandle; // handle used for status messages
DWORD ServiceNameOffset; // pointer to ServiceNameString
//xp 下固定为20,
DWORD ArgvOffset; // pointer to Argument Vectors. 指向参数部分的偏移地址
} CTRL_MSG_HEADER, *PCTRL_MSG_HEADER, *LPCTRL_MSG_HEADER;
在nt4\private\windows\screg\sc\server\control.c的ScSendControl函数中有具体发包格式
[rpc 头PORT_MESSAGE,24个字节] + [CTRL_MSG_HEADER,24 个字节] + [serviceName] +[4字节对齐] + [n个参数的的str指针,每个指针4个字节,按顺序指向后面每个字串的地址] + [n个参数字串]
加载驱动的服务的rpc头:
[rpc 头port_msg, 24个字节] +(从DataInfoOffset开始,如果它大于0)[Oif_style_header_descriptor<> ] + {-Oif_style_parameter_descriptor<6>}*
-Oif_style_header_descriptor<>描述格式是
handle_type<1>
Oi_flags<1>
[rpc_flags<4>]
proc_num<2>
stack_size<2>
[explicit_handle_description<>]
constant_client_buffer_size<2>
constant_server_buffer_size<2>
INTERPRETER_OPT_FLAGS<1>
number_of_params<1>
Parameter Descriptors的格式是,这里只说-OIF,服务就是使用这种类型,-OIF参数描述有俩种不同的方式,一种用于描述base types, 另一种用于描述其它types
Base types:
PARAM_ATTRIBUTES<2>
stack_offset<2>
type_format_char<1>
unused<1>
Other:
PARAM_ATTRIBUTES<2>
stack_offset<2>
type_offset<2>
kd> bl
0 e 77e071e9 0001 (0001) ADVAPI32!CreateServiceA
1 e 77ed44d0 0001 (0001) RPCRT4!NdrClientCall2
当在NdrClientCall2断下时
kd> db 77db6742
77db6742 00 (handle_type)48(Oi_flags) 00 00 00 00(rpc_flags) 18 00(proc_num)-44 00(stack_size) 30(FC_BIND_CONTEXT) 48 (flags )00 00(offset) 00(context_rundown_routine_index) 00(param_num) .H......D.0H....
77db6752 70 00(constant_client_buffer_size) 5c 00(constant_server_buffer_size) 46(INTERPRETER_OPT_FLAGS) 11(number_of_params) 08(extension_version) 05(INTERPRETER_OPT_FLAGS2)-00 00(ClientCorrHint) 02 00(ServerCorrHint) 00 00
(NotifyIndex) 08 00(PARAM_ATTRIBUTES) p.\.F...........
77db6762 00 00(stack_offset) 0a 00(type_offset) 0b 01 04 00-b2 01 0b 00 08 00 ac 01 ................
77db6772 48 00 0c 00 08 00 48 00-10 00 08 00 48 00 14 00 H.....H.....H...
77db6782 08 00 48 00 18 00 08 00-0b 01 1c 00 b2 01 0b 00 ..H.............
77db6792 20 00 ac 01 1a 00 24 00-54 00 0b 00 28 00 68 00 .....$.T...(.h.
77db67a2 48 00 2c 00 08 00 0b 00-30 00 ac 01 0b 00 34 00 H.,.....0.....4.
77db67b2 7c 00 48 00 38 00 08 00-10 01 3c 00 90 00 70 00 |.H.8.....<...p.
30 表示FC_BIND_CONTEXT
FC_BIND_CONTEXT的explicit_handle_description<>格式是
FC_BIND_CONTEXT flags<1> offset<2> context_rundown_routine_index<1> param_num<1>
flags 48 表示 HANDLE_PARAM_IS_IN | NDR_STRICT_CONTEXT_HANDLE
offset 00 00 在堆栈中的偏移
context_rundown_routine_index 00
param_num 00
INTERPRETER_OPT_FLAGS 46 HasExtensions | HasReturn | ClientMustSize
扩展:
size_extension_version<1> 08
INTERPRETER_OPT_FLAGS2<1> 05(ServerCorrCheck| HasNewCorrDesc )
ClientCorrHint<2> 0000
ServerCorrHint<2> 0002
NotifyIndex<2>0000
[ FloatDoubleMask<2> ]
开始参数部分:
第一个参数 08 00 00 00 0a 00
(PARAM_ATTRIBUTES) 0008 IsIn ,not base type
stack_offset 0000 --->参数在栈中的偏移,即参数地址
type_offset 000a
第二个参数 0b 01 04 00 b2 01
(PARAM_ATTRIBUTES) 010b IsSimpleRef,is in, must free, must size, not base type
stack_offset 0004
type_offset 01b2
第三个参数 0b 00 08 00 ac 01
定位参数类型,及type_offset, msdn上介绍 For other types, the type_offset<2> field gives the offset in the type format string table where the type descriptor for the argument is located.
type_offset 是索引哪里的呢?答案是
MIDL_STUB_MESSAGE
...
+const struct _MIDL_STUB_DESC* StubDesc;
....
+ const unsigned char* pFormatTypes;
就是 pFormatTypes
CLIENT_CALL_RETURN RPC_VAR_ENTRY NdrClientCall2(
__in PMIDL_STUB_DESC pStubDescriptor,
__in PFORMAT_STRING pFormat, --->77db1f60
__in_out ...
);
kd> dds 77db1f60
77db1f60 77db1fb0 ADVAPI32!`string'+0x6c
77db1f64 77db2da5 ADVAPI32!MIDL_user_allocate
77db1f68 77db2dd6 ADVAPI32!MIDL_user_free
77db1f6c 77e16294 ADVAPI32!svcctl_handle
77db1f70 00000000
77db1f74 77db23ec ADVAPI32!`string'+0x1040
77db1f78 77db23fc ADVAPI32!`string'+0x1050
77db1f7c 00000000
77db1f80 77db1ffa ADVAPI32!`string'+0xc4e ---->type_offset
typedef struct _MIDL_STUB_DESC
{
void __RPC_FAR * RpcInterfaceInformation;
void __RPC_FAR * (__RPC_FAR __RPC_API * pfnAllocate)(size_t);
void (__RPC_FAR __RPC_API * pfnFree)(void __RPC_FAR *);
union
{
handle_t __RPC_FAR * pAutoHandle;
handle_t __RPC_FAR * pPrimitiveHandle;
PGENERIC_BINDING_INFO pGenericBindingInfo;
} IMPLICIT_HANDLE_INFO;
const NDR_RUNDOWN __RPC_FAR * apfnNdrRundownRoutines;
const GENERIC_BINDING_ROUTINE_PAIR __RPC_FAR * aGenericBindingRoutinePairs;
const EXPR_EVAL __RPC_FAR * apfnExprEval;
const XMIT_ROUTINE_QUINTUPLE __RPC_FAR * aXmitQuintuple;
const unsigned char __RPC_FAR * pFormatTypes;
----->type_offset
int fCheckBounds;
/* Ndr library version. */
unsigned long Version;
/*
* Reserved for future use. (no reserves )
*/
MALLOC_FREE_STRUCT __RPC_FAR * pMallocFreeStruct;
long MIDLVersion;
const COMM_FAULT_OFFSETS __RPC_FAR * CommFaultOffsets;
// New fields for version 3.0+
const USER_MARSHAL_ROUTINE_QUADRUPLE __RPC_FAR * aUserMarshalQuadruple;
long Reserved1;
long Reserved2;
long Reserved3;
long Reserved4;
long Reserved5;
} MIDL_STUB_DESC;
typedef const unsigned char __RPC_FAR * PFORMAT_STRING;
参数类型:
kd> db 77db1ffa
77db1ffa 00 00 11 04 02 00 30 e9-00 00 30 49 00 00 11 04 ......0...0I....
77db200a 02 00 15 03 1c 00 08 08-08 08 08 08 08 5b 11 04 .............[..
77db201a 02 00 30 a8 01 01 11 00-02 00 1b 00 01 00 29 00 ..0...........).
77db202a 0c 00 00 00 02 5b b7 08-00 00 00 00 00 00 04 00 .....[..........
77db203a 11 0c 08 5c 11 00 cc ff-11 04 02 00 30 e9 01 00 ...\........0...
77db204a 12 08 25 5c 12 08 08 5c-12 00 02 00 1b 00 01 00 ..%\...\........
77db205a 29 00 20 00 00 00 02 5b-12 00 02 00 1b 00 01 00 ). ....[........
77db206a 29 00 2c 00 00 00 02 5b-11 08 25 5c 12 00 02 00 ).,....[..%\....
第一个参数类型 type_offset 000a, pFormatTypes[000a] = 30 ,pFormatTypes是指向char字符的指针。关于数字代表的类型,在
http://msdn.microsoft.com/en-us/library/windows/desktop/aa374387(v=vs.85).aspx
http://doxygen.reactos.org/df/d78/ndrtypes_8h_a3a87921fd20c99c442f820551f85261e.html
该值30表示FC_BIND_CONTEXT,格式为
FC_BIND_CONTEXT flags<1> offset<2> context_rundown_routine_index<1> param_num<1>
Note A context handle description in the type format string will not have the offset<2> in the description.所以应该是
FC_BIND_CONTEXT flags<1> context_rundown_routine_index<1> param_num<1>
即49 (HANDLE_PARAM_IS_IN | NDR_STRICT_CONTEXT_HANDLE | NDR_CONTEXT_HANDLE_CANNOT_BE_NULL) 00 00.
第二个参数类型 type_offset 01b2 , pFormatTypes[01b2] = 22,
简单类型封装在函数中,复杂类型在表中,表为
const PMARSHALL_ROUTINE MarshallRoutinesTable[] =
{
NdrPointerMarshall,
NdrPointerMarshall,
NdrPointerMarshall,
NdrPointerMarshall,
NdrSimpleStructMarshall,
NdrSimpleStructMarshall,
NdrConformantStructMarshall,
NdrConformantStructMarshall,
NdrConformantVaryingStructMarshall,
NdrComplexStructMarshall,
NdrConformantArrayMarshall,
NdrConformantVaryingArrayMarshall,
NdrFixedArrayMarshall,
NdrFixedArrayMarshall,
NdrVaryingArrayMarshall,
NdrVaryingArrayMarshall,
NdrComplexArrayMarshall,
NdrConformantStringMarshall,
NdrConformantStringMarshall,
NdrConformantStringMarshall,
NdrConformantStringMarshall,
NdrNonConformantStringMarshall,
NdrNonConformantStringMarshall,
NdrNonConformantStringMarshall,
NdrNonConformantStringMarshall,
NdrEncapsulatedUnionMarshall,
NdrNonEncapsulatedUnionMarshall,
NdrByteCountPointerMarshall,
NdrXmitOrRepAsMarshall, // transmit as
NdrXmitOrRepAsMarshall, // represent as
NdrInterfacePointerMarshall,
NdrMarshallHandle,
// New Post NT 3.5 token serviced from here on.
NdrHardStructMarshall,
NdrXmitOrRepAsMarshall, // transmit as
ptr
NdrXmitOrRepAsMarshall, // represent as ptr
NdrUserMarshalMarshall
};
NdrClientCall2(本篇看到的消息格式)->RPCRT4!NdrpClientMarshal(对消息封装)->NdrSendReceive->I_RpcSendReceive->MESSAGE_OBJECT::SendReceive->WMSG_CCALL::AsyncSendReceive(填充rpc头)->WMSG_CCALL::AsyncSendReceiveHelper->NtRequestWaitReplyPort
创建服务堆栈:
kd> kv
ChildEBP RetAddr Args to Child
0012f224 77e5cac1 000000ac 00147f68 00147f68 ntdll!ZwRequestWaitReplyPort (FPO: [3,0,0])
0012f270 77e5a33e 0014d830 0012f290 77e5a36f RPCRT4!LRPC_CCALL::SendReceive+0x228 (FPO: [Non-Fpo])
0012f27c 77e5a36f 0012f2ac 77db1f60 0012f688 RPCRT4!I_RpcSendReceive+0x24 (FPO: [Non-Fpo])
0012f290 77ed4675 0012f2d8 0014d8e8 00000000 RPCRT4!NdrSendReceive+0x2b (FPO: [Non-Fpo])
0012f66c 77e081f1 77db1f60 77db6742 0012f688 RPCRT4!NdrClientCall2+0x222 (FPO: [Non-Fpo])
0012f680 77e072fd 00151dc8 00386108 00386108 ADVAPI32!RCreateServiceA+0x1b (FPO: [Non-Fpo])
0012f714 0040290d 00151dc8 00386108 00386108 ADVAPI32!CreateServiceA+0x114 (FPO: [Non-Fpo])
WARNING: Stack unwind information not available. Following frames may be wrong.
0012f77c 73d323bf 0012fd44 00000001 00000000 InstDrv+0x290d
封装参数堆栈
kd> kv
ChildEBP RetAddr Args to Child
0012f290 77ed463c 0012f2d8 00000000 00000000 RPCRT4!NdrpClientMarshal (FPO: [Non-Fpo])
0012f66c 77e081f1 77db1f60 77db6742 0012f688 RPCRT4!NdrClientCall2+0x1c8 (FPO: [Non-Fpo])
0012f680 77e072fd 00151bd0 003860b8 003860b8 ADVAPI32!RCreateServiceA+0x1b (FPO: [Non-Fpo])
0012f714 0040290d 00151bd0 003860b8 003860b8 ADVAPI32!CreateServiceA+0x114 (FPO: [Non-Fpo])
WARNING: Stack unwind information not available. Following frames may be wrong.
0012f77c 73d323bf 0012fd44 00000001 00000000 InstDrv+0x290d
有了上面的信息之后,总算可以分析核心函数NdrpClientMarshal了。
1) 参数的占用的内存大小
计算是在NdrpSizing这个函数里面做的。根据不同的类型去索引表SizeRoutinesTable来计算相关大小。
2) 封装参数
NdrpClientMarshal
RPCRT4!NdrpClientMarshal:
001b:77e58aa0 8bff mov edi,edi
001b:77e58aa2 55 push ebp
001b:77e58aa3 8bec mov ebp,esp
001b:77e58aa5 83ec0c sub esp,0Ch
001b:77e58aa8 8365fc00 and dword ptr [ebp-4],0
001b:77e58aac 53 push ebx
001b:77e58aad 8b5d08 mov ebx,dword ptr [ebp+8] ;PMIDL_STUB_MESSAGE
001b:77e58ab0 57 push edi
001b:77e58ab1 8bbbc4000000 mov edi,dword ptr [ebx+0C4h] ;struct _NDR_PROC_CONTEXT* pContext;
001b:77e58ab7 837f1000 cmp dword ptr [edi+10h],0
001b:77e58abb 8b4728 mov eax,dword ptr [edi+28h]
001b:77e58abe 8b5714 mov edx,dword ptr [edi+14h]
;
;根据弄到的值推算就是PFORMAT_STRING pFormat 参数描述开始部分。
;1: kd> r edx
; edx=77db6b96
; pFormat 77db6b74
; ? 77db6b96 - 77db6b74 == 34刚好是描述头的大小
001b:77e58ac1 897d08 mov dword ptr [ebp+8],edi
001b:77e58ac4 8945f4 mov dword ptr [ebp-0Ch],eax
001b:77e58ac7 7663 jbe RPCRT4!NdrpClientMarshal+0x104 (77e58b2c)
001b:77e58ac9 83c204 add edx,4
001b:77e58acc 8955f8 mov dword ptr [ebp-8],edx ;pFormat_Pra
001b:77e58acf 56 push esi
;@@@@参数从这里开始处理
001b:77e58ad0 668b4afc mov cx,word ptr [edx-4] ds:0023:77db6b92=0008
001b:77e58ad4 f6c108 test cl,8 ;IsIn
001b:77e58ad7 7441 je RPCRT4!NdrpClientMarshal+0xee (77e58b1a)
001b:77e58ad9 f6c104 test cl,4 ;IsPipe
001b:77e58adc 753c jne RPCRT4!NdrpClientMarshal+0xee (77e58b1a)
;只对 有 IsIn 而且不没有IsPipe属性的 参数进行Marshall
001b:77e58ade 0fb772fe movzx esi,word ptr [edx-2] ; 参数的堆栈偏移
001b:77e58ae2 037718 add esi,dword ptr [edi+18h] ;[edi+18h] 就是参数堆栈的基地址
001b:77e58ae5 f6c508 test ch,8
001b:77e58ae8 0f85e8990300 jne RPCRT4!NdrpClientMarshal+0x56 (77e924d6)
001b:77e58aee f6c140 test cl,40h ;是否IsBasetype,基础类型不走MarshallRoutines
001b:77e58af1 0f85d10b0000 jne RPCRT4!NdrpClientMarshal+0x76 (77e596c8)
001b:77e58af7 0fb702 movzx eax,word ptr [edx] ;type_offset
001b:77e58afa 0345f4 add eax,dword ptr [ebp-0Ch] ;获取类型描述
001b:77e58afd 84c9 test cl,cl
001b:77e58aff 7802 js RPCRT4!NdrpClientMarshal+0xd7 (77e58b03)
001b:77e58b01 8b36 mov esi,dword ptr [esi] ; 取参数,就是00154be0,就是句柄的值
001b:77e58b03 33c9 xor ecx,ecx
001b:77e58b05 8a08 mov cl,byte ptr [eax] ;eax的第一个字节就是参数的类型
;开始进行数据封装
001b:77e58b07 50 push eax ;PFORMAT_STRING pFormat,但是从参数描述开始的
001b:77e58b08 56 push esi ;参数
001b:77e58b09 53 push ebx ;pStubMsg
001b:77e58b0a 83e13f and ecx,3Fh
001b:77e58b0d ff148d7814e577 call dword ptr RPCRT4!MarshallRoutinesTable (77e51478)[ecx*4]
001b:77e58b14 8b55f8 mov edx,dword ptr [ebp-8]
001b:77e58b17 8b7d08 mov edi,dword ptr [ebp+8]
001b:77e58b1a ff45fc inc dword ptr [ebp-4]
001b:77e58b1d 8b45fc mov eax,dword ptr [ebp-4]
001b:77e58b20 83c206 add edx,6 ;因为参数描述结构的大小是6字节
001b:77e58b23 3b4710 cmp eax,dword ptr [edi+10h] ds:0023:0012fa5c=00000006 ;[edi+10h]保存参数个数
001b:77e58b26 8955f8 mov dword ptr [ebp-8],edx
001b:77e58b29 72a5 jb RPCRT4!NdrpClientMarshal+0x34 (77e58ad0)
好,下面看NDR怎么处理 IsBasetype 为TRUE的参数
001b:77e596c8 f6c501 test ch,1 ;MustSize
001b:77e596cb 0f8527240000 jne RPCRT4!NdrpClientMarshal+0x7b (77e5baf8) [br=0]
001b:77e596d1 803a0d cmp byte ptr [edx],0Dh ;type_format_char, D == FC_ENUM16
001b:77e596d4 0f84cd9e0000 je RPCRT4!NdrpClientMarshal+0x82 (77e635a7)
;通过 type_format_char 索引 RPCRT4!SimpleTypeAlignment,基础类型的对齐大小
001b:77e596da 0fb602 movzx eax,byte ptr [edx]
001b:77e596dd 0fb6805816e577 movzx eax,byte ptr RPCRT4!SimpleTypeAlignment (77e51658)[eax]
001b:77e596e4 8b7b04 mov edi,dword ptr [ebx+4] ; 0012fcfc, MIDL_STUB_MESSAGE::Buffer
001b:77e596e7 03f8 add edi,eax
001b:77e596e9 f7d0 not eax
001b:77e596eb 23f8 and edi,eax
001b:77e596ed 897b04 mov dword ptr [ebx+4],edi
;通过 type_format_char 索引 RPCRT4!SimpleTypeBufferSize,基础类型的大小
001b:77e596f0 0fb602 movzx eax,byte ptr [edx]
001b:77e596f3 0fb6881817e577 movzx ecx,byte ptr RPCRT4!SimpleTypeBufferSize (77e51718)[eax]
;开始复制参数
001b:77e596fa 8bc1 mov eax,ecx
001b:77e596fc c1e902 shr ecx,2
001b:77e596ff f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
001b:77e59701 8bc8 mov ecx,eax
001b:77e59703 83e103 and ecx,3
001b:77e59706 f3a4 rep movs byte ptr es:[edi],byte ptr [esi]
001b:77e59708 0fb602 movzx eax,byte ptr [edx]
001b:77e5970b 0fb6801817e577 movzx eax,byte ptr RPCRT4!SimpleTypeBufferSize (77e51718)[eax]
001b:77e59712 014304 add dword ptr [ebx+4],eax
001b:77e59715 e9fdf3ffff jmp RPCRT4!NdrpClientMarshal+0xeb (77e58b17)
001b:77e5971a f6c401 test ah,1
001b:77e5971d 0f85dc230000 jne RPCRT4!NdrpServerUnMarshal+0x9a (77e5baff)
001b:77e59723 33c0 xor eax,eax
001b:77e59725 8a4704 mov al,byte ptr [edi+4]
001b:77e59728 50 push eax
上面可知参数处理后是放在 MIDL_STUB_MESSAGE::Buffer 里面的
发送消息类型:
typedef union _WMSG_MESSAGE
{
WMSG_CONNECT_MESSAGE Connect;
WMSG_BIND_MESSAGE Bind;
WMSG_RPC_MESSAGE Rpc;
WMSG_FAULT_MESSAGE Fault;
WMSG_CLOSE_MESSAGE Close;
PORT_MESSAGE LpcHeader;
WMSG_RESPONSE_MESSAGE Response ;
WMSG_ACK_MESSAGE Ack ;
WMSG_PUSH_MESSAGE Push ;
WMSG_BIND_BACK_MESSAGE BindBack ;
WMSG_PARTIAL_MESSAGE Partial ;
} WMSG_MESSAGE;
服务的rpc msg格式是:
typedef struct _WMSG_RPC_MESSAGE
{
PORT_MESSAGE LpcHeader;
---> 格式前面有 24 字节
WMSG_RPC_HEADER RpcHeader;
---> Oif_style_header_descriptor 共0x38个字节
union
{
unsigned char Buffer[MAXIMUM_MESSAGE_BUFFER];
---->参数,自保中的ParamOffset.
PORT_DATA_INFORMATION Request;
WMSG_SERVER_BUFFER Server;
};
} WMSG_RPC_MESSAGE;
typedef struct _WMSG_RPC_HEADER
{
unsigned char MessageType;
unsigned char Flags ;
unsigned char PresentationContext;
unsigned char ObjectUuidFlag;
unsigned short ProcedureNumber;
unsigned short ConnectionKey ;
UUID ObjectUuid;
} WMSG_RPC_HEADER;
NtRequestWaitReplyPort参数中的PortHandle是自己端口对象。
typedefstruct_LPCP_PORT_OBJECT{
struct_LPCP_PORT_OBJECT *ConnectionPort;
struct_LPCP_PORT_OBJECT *ConnectedPort;
LPCP_PORT_QUEUEMsgQueue;
CLIENT_ID Creator;
……
}LPCP_PORT_OBJECT, *PLPCP_PORT_OBJECT;
过滤时比较主要的就是ConnectionPort,这里面指向的是对方端口对象,得到对方端口对象后查询对象名,services建立的服务端口名是 \RPC Control\ntsvcs
在buffer中的数据封装:
基本类型,字节对齐,然后是数据直接拷到buffer。
字符串,先对齐,然后maxCount,然后对齐,然后0占4个字节,然后4个字节的字符串实际长度,然后字符串的ascii码。然后空4个字节,然后是下个参数。
在函数NdrConformantStringMarshall中封装。如果已经对齐就不填充字节。字符串需要按sizeof(ulong)对齐,即如果字串"mysys",5个字节,加一个'\0',共
6个字节,按4字节对齐,后面的内容存需要加上8给字节对齐。
猜测createService的bprotect过滤中,参数+20个字节才是服务名,是因为4个字节的 explicit handle +16字节的 sc_handle结构
--写于2013-12-20