Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@exelix11
Last active May 4, 2019 09:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save exelix11/6f12103d53652a13781af37e893e86f5 to your computer and use it in GitHub Desktop.
Save exelix11/6f12103d53652a13781af37e893e86f5 to your computer and use it in GitHub Desktop.
mitm and block ipc requests for the Yi IOT cameras
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <mqueue.h>
#include <unistd.h>
#define LOGGING
//#define NOPRINT
#if defined(LOGGING)
FILE *logFile = NULL;
#define printf(...) do { fprintf(logFile, __VA_ARGS__); fflush(logFile); } while(0)
#elif defined(NOPRINT)
#define printf(...) do { } while(0)
#endif
int patchProgram(const char* elfPath, const char* targetIpc, const char* saveas)
{
FILE *f = fopen(elfPath, "rb");
if (!f)
{
printf("Path not found !\n");
return -1;
}
fseek(f,0,SEEK_END);
long int flen = ftell(f);
fseek(f,0,SEEK_SET);
char *buf = malloc(flen);
fread(buf,1,flen,f);
fclose(f);
f = NULL;
int ipcLen = strlen(targetIpc);
for (int i = 0; i < flen - ipcLen; i++)
if (memcmp(targetIpc, buf + i, ipcLen + 1) == 0)
{
printf("Found target at %x\n", i);
buf[i + 1] = 'm';
}
f = fopen(saveas, "wb");
if (!f)
{
printf("could not open output file\n");
free(buf);
return -2;
}
fwrite(buf,1,flen,f);
fclose(f);
printf("Patched and saved as %s", saveas);
free(buf);
return 0;
}
enum MitmAction
{
MITM_NO_CHANGE = -1,
MITM_BLOCK = 0
};
/*
A patch function can return either MITM_BLOCK, MITM_NO_CHANGE or a new size for the message.
When returning MITM_NO_CHANGE the buffer should not be modified as it will be passed to the next patch function for the queue.
When returning MITM_BLOCK the message will be blocked and won't be passed to other patch functions.
When returning a size the message will be immediately forwarded without passing through other functions, it's possible to increase or reduce the size as well to edit the buffer.
*/
typedef int (*PatchFunction)(char*, int);
void dumpHex(char *buf, int len)
{
for (int i = 0; i < len; i++)
printf("%.2x ", buf[i]);
}
int MitmQueue(const char* QueueName, PatchFunction* patchFn)
{
char mitmName[strlen(QueueName) + 1];
strcpy(mitmName, QueueName);
mitmName[1] = 'm';
printf("mitming %s -> %s\n", QueueName, mitmName);
mqd_t readQueue;
mqd_t sendQueue;
struct mq_attr ma;
ma.mq_flags = 0;
ma.mq_maxmsg = 16;
ma.mq_msgsize = 512;
ma.mq_curmsgs = 0;
readQueue = mq_open(QueueName, O_RDONLY | O_CREAT, 438, &ma);
if (readQueue == -1)
{
printf("Error opening the mitm queue %s\n", mitmName);
return -2;
}
sendQueue = mq_open(mitmName, O_WRONLY | O_CREAT, 438, &ma);
if (sendQueue == -1)
{
printf("Error opening the real queue %s\n", QueueName);
return -3;
}
while (1) {
char msgBuf[512];
ssize_t len = mq_receive(readQueue, msgBuf, 512, NULL);
if (len == -1)
{
printf("Error receiving the message\n");
return -4;
}
printf("msg len 0x%x ", len);
#if !defined(NOPRINT)
if (len < 32) dumpHex(msgBuf,len);
#endif
if (patchFn)
{
PatchFunction* p = patchFn;
while (*p)
{
int res = (*p)(msgBuf,len);
if (res != MITM_NO_CHANGE)
{
len = res;
break;
}
p++;
}
if (len == 0)
{
printf("blocked by patchFn !\n");
continue;
}
}
ssize_t sent = mq_send(sendQueue, msgBuf, len, 1);
if (sent == -1)
{
printf("Error sending the message\n");
return -5;
}
printf("sent ! %x\n", sent);
}
return 0;
}
int rmm(char* buf, int len)
{
if (len != 16) return MITM_NO_CHANGE;
int *arr = (int*)buf;
if (arr[0] == 1 && arr[1] == 2 && arr[2] == 0x7C007C && arr[3] == 0)
if (access("/tmp/rec_vid",0)) //block the message if this file isn't there
return MITM_BLOCK;
else
printf("(motion_start msg allowed) ");
return MITM_NO_CHANGE;
}
typedef struct FunctionEntry
{
PatchFunction fn;
const char* name;
const char* desc;
} FunctionEntry_t;
FunctionEntry_t entries[] =
{
{rmm, "rmm", "this is used to block recordings if the file /tmp/rec_vid doesn't exist"},
{NULL, NULL, NULL}
};
int main(int argc, char** argv)
{
#if defined(LOGGING)
logFile = fopen("/tmp/mitmlog", "w");
#endif
printf("IpcMitm\n");
if (argc == 2)
return MitmQueue(argv[1], NULL);
else if (argc == 5 && !strcmp(argv[1],"patch"))
return patchProgram(argv[2], argv[3], argv[4]);
else if (argc >= 3)
{
PatchFunction functions[argc - 1]; //there's one extra slot at the end to break the loop in MitmQueue
memset(functions,0, sizeof(PatchFunction) * argc - 1);
for (int i = 2; i < argc; i++)
{
for (int j = 0; entries[j].fn; j++)
if (!strcmp(argv[i], entries[j].name))
{
functions[i - 2] = entries[j].fn;
break;
}
if (functions[i - 2]) continue;
printf("Couldn't find '%s' patch function !\n", argv[i]);
goto NoMatch;
}
MitmQueue(argv[1], functions);
}
else
{
NoMatch:
printf( "Usage:\n"
"IpcMitm <queue name>: mitms the specified queue, only for patched binaries. (just logs messages)\n"
"IpcMitm <queue name> <handler function 1> <handler function 2> .....: like the one before but the handler function may block or edit some before forwarding them\n"
"IpcMitm patch <input file> <queue name> <output file>: patches an executable to use a mitm'd version of the specified queue\n"
"List of patch functions:\n");
for (int i = 0; entries[i].fn ; i++)
printf("%s : %s\n", entries[i].name, entries[i].desc);
}
#if defined(LOGGING)
fclose(logFile);
#endif
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment