RPC总结

 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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值