mirror of
https://gitea.tendokyu.moe/TeamTofuShop/capnhook.git
synced 2026-09-25 07:47:56 +03:00
194 lines
4.0 KiB
C
194 lines
4.0 KiB
C
#include <assert.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "inject/options.h"
|
|
|
|
void options_help(FILE *f)
|
|
{
|
|
assert(f != NULL);
|
|
|
|
fputs( "Usage: inject [options] program args...\n"
|
|
"All options must precede the program name.\n"
|
|
"\n"
|
|
"The following options are understood:\n"
|
|
"\n"
|
|
"-h\tPrint this message.\n"
|
|
"\n"
|
|
"-d\tAttach to target as a debugger and print debug messages.\n"
|
|
"\n"
|
|
"-p\tPause the target until a debugger attaches to it.\n"
|
|
" \tCannot be used with -d.\n"
|
|
"\n"
|
|
"-w\tWait for target to terminate.\n"
|
|
" \tCannot be used with -d.\n"
|
|
"\n"
|
|
"-k dll\tInject the named DLL into the target process.\n"
|
|
" \tCan be specified more than once.\n"
|
|
"\n",
|
|
f);
|
|
}
|
|
|
|
HRESULT options_init(struct options *opt, int argc, char **argv)
|
|
{
|
|
int nconsumed;
|
|
const char *arg;
|
|
int i;
|
|
|
|
assert(opt != NULL);
|
|
|
|
memset(opt, 0, sizeof(*opt));
|
|
nconsumed = 1;
|
|
|
|
for (i = 1 ; i < argc && argv[i][0] == '-' ; i++) {
|
|
arg = argv[i];
|
|
nconsumed++;
|
|
|
|
switch (arg[1]) {
|
|
case 'h':
|
|
opt->help = true;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
if (opt->debug_pause || opt->wait) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
opt->debug = true;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
if (opt->debug) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
opt->debug_pause = true;
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
if (opt->debug) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
opt->wait = true;
|
|
|
|
break;
|
|
|
|
case 'k':
|
|
if (i + 1 >= argc) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* These get pulled by options_next_dll. Consume its argument as
|
|
well though. */
|
|
|
|
nconsumed++;
|
|
i++;
|
|
|
|
break;
|
|
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
if (nconsumed == argc) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
opt->orig_argc = argc;
|
|
opt->orig_argv = argv;
|
|
opt->target_argc = argc - nconsumed;
|
|
opt->target_argv = argv + nconsumed;
|
|
opt->dll_pos = 1;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT options_target_cmdline(const struct options *opt, char **out)
|
|
{
|
|
char *str;
|
|
char *pos;
|
|
size_t nchars;
|
|
size_t len;
|
|
int i;
|
|
|
|
assert(opt != NULL);
|
|
assert(out != NULL);
|
|
|
|
*out = NULL;
|
|
|
|
/* Measure string. Each element requires an opening quote, a closing quote
|
|
and either a trailing space or a trailing NUL. */
|
|
|
|
nchars = 3 * opt->target_argc;
|
|
|
|
for (i = 0 ; i < opt->target_argc ; i++) {
|
|
nchars += strlen(opt->target_argv[i]);
|
|
}
|
|
|
|
str = malloc(nchars);
|
|
|
|
if (str == NULL) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
/* Construct string. This doesn't escape quotes within individual args yet
|
|
but ugh I'll fix that later if it really becomes necessary, it's a pain
|
|
to deal with. */
|
|
|
|
for (i = 0, pos = str ; i < opt->target_argc ; i++) {
|
|
len = strlen(opt->target_argv[i]);
|
|
|
|
*pos++ = '"';
|
|
memcpy(pos, opt->target_argv[i], len);
|
|
pos += len;
|
|
*pos++ = '"';
|
|
|
|
if (i + 1 < opt->target_argc) {
|
|
*pos++ = ' ';
|
|
} else {
|
|
*pos++ = '\0';
|
|
}
|
|
}
|
|
|
|
*out = str;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT options_next_dll(struct options *opt, const char **out)
|
|
{
|
|
const char *arg;
|
|
|
|
assert(opt != NULL);
|
|
assert(opt->orig_argv != NULL);
|
|
assert(out != NULL);
|
|
|
|
*out = NULL;
|
|
|
|
while (opt->dll_pos < opt->orig_argc) {
|
|
arg = opt->orig_argv[opt->dll_pos];
|
|
|
|
if (arg[0] != '-') {
|
|
break;
|
|
}
|
|
|
|
opt->dll_pos++;
|
|
|
|
if (arg[1] == 'k' && opt->dll_pos < opt->orig_argc) {
|
|
*out = opt->orig_argv[opt->dll_pos++];
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|