PDA

View Full Version : Minimal RPC through LPC calls


BanMe
July 12th, 2010, 22:38
So this is just a overview of one of the 'features' in the 'subsystem' addon I am in process of creating..This article expects you understand LPC communication.

RPC or Remote Procedure Call is a term that can be taken as calling remote 'procedures' in a remote 'process', this has been done in numerous ways, COBRA and such, but here I present a very simple and easy to extend Remote procedure call interface.

The first thing you need to do, is determine what procedures you want to call and what parameters you will be using to call them with, if parameters are needed at all.

so lets say we want to Call Sleep

Code:

invoke Sleep 0x10000


so this call can be broken down into its base elements represented.
Code:

Address = GetProcAddress(*,"Sleep";
Data = 0x10000;


So the 2nd thing you need is a minimal LPC Server and Client. server should be a exe with a GUI. client has to be either a Dll or code included into server for injection.

the client can look like anything and do w/e but the message handler needs to look like this.
Code:

Code:

typedef ULONG(NTAPI*RpcApiWithParameter)(void*);
typedef ULONG(NTAPI*RpcApi)(void);

Status = NtRequestWaitReplyPort(PortHandle,(PORT_MESSAGE*)&ApiReplyMessage,(PORT_MESSAGE*)&ApiRecvMessage);
switch(ApiRecvMessage.Status)
{
case 0://do nothing wait for further instruction ...
{
goto WaitForServer;
}
case 1://execute Api Mapped into client process by server
{
if(ApiRecvMessage.StartAddress == 0)
{
goto WaitForServer;
}
else
{
if(ApiRecvMessage.Data != 0)
{
pClientApi = (RpcApiWithParameter)ApiRecvMessage.StartAddress;
pClientApi((void*)ApiRecvMessage.Data);
goto WaitForServer;
}
else
{
ClientApi = (RpcApi)ApiRecvMessage.StartAddress;
ClientApi();
goto WaitForServer;
}
}
}
}


Most of this code should be understandable to you, the only thing further is we need to adapt the PORT_MESSAGE structure to fit our needs...

Code:

typedef struct _RPC_MESSAGE
{
PORT_MESSAGE Header;
ULONG Data;
ULONG Status;
ULONG StartAddress;
}RPC_MESSAGE, *PRPC_MESSAGE;




and In the Server this code will send the Message to the client to call sleep.

Code:

RPC_MESSAGE ApiReplyMessage = {0};
InitializeMessageHeader(&ApiReplyMessage.Header,sizeof(RPC_MESSAGE),LPC_NEW_MESSAGE);
ApiReplyMessage.Data = 0x10000;
ApiReplyMessage.StartAddress = (ULONG)Native_GetApi(L"kernel32.dll","Sleep";
ApiReplyMessage.Status = 1;
NtReplyPort(ThisEntry->Port,(PORT_MESSAGE*)&ApiReplyMessage);


Ty for taking your time to read this, comments are welcomed.

regards BanMe

BanMe
July 18th, 2010, 10:29
So part 2 of this small 'feature' is about using that 'shared' sections with RPC...So calling a 'single' api remotely turns into calling a 'given' instructional pattern remotely in 1 call..

This requires a additional modification of RPC_MESSAGE to include info about ClientView and ServerView

Code:

typedef struct _RPC_MESSAGE
{
PORT_MESSAGE Header;
ULONG Data;
ULONG Status;
ULONG StartAddress;
PORT_VIEW ServerView;
REMOTE_PORT_VIEW ClientView;
}RPC_MESSAGE, *PRPC_MESSAGE;


This basic next step is getting code from 'server' to client. This can be seen here..
Code:

ClientId.UniqueProcess = ApiRecvMessage.Header.ClientId.UniqueProcess;
ClientId.UniqueThread= ApiRecvMessage.Header.ClientId.UniqueThread;
memcpy(ApiRecvMessage->ServerView.ViewBase,&DATA,sizeof(DATA_STRUCTURE));
memcpy((void*)((ULONG)ApiRecvMessage->ServerView.ViewBase+sizeof(DATA_STRUCTURE)),AddressOfRoutineToCall,GetFunctionLength(AddressOfRoutin eToCall));
ApiReplyMessage.Data = (ULONG)ApiRecvMessage->ClientView.ViewBase;
ApiReplyMessage.StartAddress = ((ULONG)ApiRecvMessage->ClientView.ViewBase+sizeof(DATA_STRUCTURE));
ApiReplyMessage.Status = 1;
break;


Some ambigious names are used in the code for clarities sake :P
and when you actualy send the reply messsage dont forget to fillout the additional structures :}

regards BanMe