2022-06-20 06:28:03 +00:00
|
|
|
|
|
|
|
// Windows symbols because windows
|
|
|
|
int _fltused=0;
|
|
|
|
|
2022-07-30 05:15:11 +00:00
|
|
|
#define CMDLINE_CMD_MAX 32767
|
|
|
|
#define CMDLINE_ARGV_MAX (16384+(98298+(int)sizeof(char*))/(int)sizeof(char*))
|
|
|
|
|
2022-06-20 06:28:03 +00:00
|
|
|
extern int main(int argc, char** argv);
|
|
|
|
|
|
|
|
// Exit routines
|
2022-06-27 02:04:46 +00:00
|
|
|
#define ATEXIT_FUNC_COUNT 64
|
|
|
|
#define ATQEXIT_FUNC_COUNT 64
|
|
|
|
static void (*atexit_funcs [ATEXIT_FUNC_COUNT])(void);
|
|
|
|
static void (*atqexit_funcs[ATQEXIT_FUNC_COUNT])(void);
|
2022-06-20 06:28:03 +00:00
|
|
|
static int atexit_func_count;
|
2022-06-27 02:04:46 +00:00
|
|
|
static int atqexit_func_count;
|
2022-06-20 06:28:03 +00:00
|
|
|
|
2022-06-27 02:04:46 +00:00
|
|
|
static char **get_command_args(int *argc_ptr);
|
2022-06-20 06:28:03 +00:00
|
|
|
|
|
|
|
void mainCRTStartup() {
|
|
|
|
// Set-up some platform stuff
|
|
|
|
_setup_eh();
|
2022-06-21 13:32:46 +00:00
|
|
|
_setup_heap();
|
2022-06-20 06:28:03 +00:00
|
|
|
_setup_timer();
|
2022-06-21 13:32:46 +00:00
|
|
|
_setup_io();
|
2022-06-20 06:28:03 +00:00
|
|
|
|
|
|
|
// Set-up CRT stuff
|
|
|
|
srand(0);
|
|
|
|
setlocale(LC_ALL, "C");
|
|
|
|
|
|
|
|
// Parse command-line arguments
|
|
|
|
int argc;
|
|
|
|
char **args = get_command_args(&argc);
|
|
|
|
int exit_code = main(argc, args);
|
|
|
|
|
|
|
|
// we call exit because we want atexit routines run
|
2022-06-24 01:38:54 +00:00
|
|
|
// and all the file handles to be freed
|
2022-06-20 06:28:03 +00:00
|
|
|
exit(exit_code);
|
|
|
|
}
|
|
|
|
|
2022-06-27 02:04:46 +00:00
|
|
|
|
|
|
|
_Noreturn void quick_exit(int status) {
|
|
|
|
while(atqexit_func_count--) {
|
|
|
|
atqexit_funcs[atqexit_func_count]();
|
|
|
|
}
|
|
|
|
ExitProcess(status);
|
|
|
|
}
|
|
|
|
|
2022-06-24 01:38:54 +00:00
|
|
|
_Noreturn void exit(int status) {
|
2022-06-27 02:04:46 +00:00
|
|
|
while(atexit_func_count--) {
|
|
|
|
atexit_funcs[atqexit_func_count]();
|
2022-06-24 01:38:54 +00:00
|
|
|
}
|
|
|
|
_close_io();
|
|
|
|
ExitProcess(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
_Noreturn void _Exit(int status) {
|
|
|
|
ExitProcess(status);
|
|
|
|
}
|
2022-06-20 06:28:03 +00:00
|
|
|
|
|
|
|
_Noreturn void abort(void) {
|
|
|
|
raise(SIGABRT);
|
|
|
|
ExitProcess(-69);
|
|
|
|
}
|
|
|
|
|
|
|
|
int atexit(void (*func)(void)) {
|
|
|
|
if (atexit_func_count >= ATEXIT_FUNC_COUNT) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
atexit_funcs[atexit_func_count++] = func;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-06-27 02:04:46 +00:00
|
|
|
int at_quick_exit(void (*func)(void)) {
|
|
|
|
if(atqexit_func_count >= ATQEXIT_FUNC_COUNT) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
atqexit_funcs[atqexit_func_count++] = func;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-06-20 06:28:03 +00:00
|
|
|
char *getenv(const char *name) {
|
|
|
|
// The string pointed to shall not be modified by the program, but may be
|
|
|
|
// overwritten by a subsequent call to the getenv function
|
|
|
|
static size_t env_string_cap;
|
|
|
|
static char* env_string;
|
|
|
|
|
|
|
|
DWORD env_length = GetEnvironmentVariable(name, NULL, 0);
|
|
|
|
if (env_length == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upscale the internal string
|
|
|
|
if (env_length > env_string_cap) {
|
|
|
|
char* newstr = realloc(env_string, env_length);
|
|
|
|
if (newstr == NULL) {
|
|
|
|
free(env_string);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
env_string = newstr;
|
|
|
|
env_string_cap = env_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
GetEnvironmentVariable(name, env_string, env_length);
|
|
|
|
return env_string;
|
|
|
|
}
|
2022-06-21 13:32:46 +00:00
|
|
|
|
|
|
|
int system(const char* string) {
|
|
|
|
int wchars_required = MultiByteToWideChar(65001, 0, string, -1, NULL, 0);
|
|
|
|
wchar_t* cmd_line = malloc(sizeof(L"cmd.exe ") + (wchars_required * sizeof(wchar_t)));
|
|
|
|
if (cmd_line == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(cmd_line, L"cmd.exe ", sizeof(L"cmd.exe "));
|
|
|
|
MultiByteToWideChar(65001, 0, string, -1, cmd_line + sizeof("cmd.exe ") - 1, wchars_required);
|
|
|
|
|
|
|
|
STARTUPINFOW si = {
|
|
|
|
.cb = sizeof(STARTUPINFOW),
|
|
|
|
.dwFlags = STARTF_USESTDHANDLES,
|
|
|
|
.hStdInput = GetStdHandle(STD_INPUT_HANDLE),
|
|
|
|
.hStdError = GetStdHandle(STD_ERROR_HANDLE),
|
|
|
|
.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)
|
|
|
|
};
|
|
|
|
PROCESS_INFORMATION pi = {};
|
|
|
|
|
|
|
|
if (!CreateProcessW(NULL, cmd_line, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait until child process exits.
|
|
|
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
|
|
|
|
|
|
DWORD exit_code;
|
|
|
|
if (!GetExitCodeProcess(pi.hProcess, &exit_code)) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close process and thread handles.
|
|
|
|
CloseHandle(pi.hProcess);
|
|
|
|
CloseHandle(pi.hThread);
|
|
|
|
free(cmd_line);
|
|
|
|
return exit_code;
|
|
|
|
|
|
|
|
error:
|
|
|
|
free(cmd_line);
|
|
|
|
return -1;
|
|
|
|
}
|
2022-06-27 02:04:46 +00:00
|
|
|
|
|
|
|
int _wcsicmp(wchar_t const* s1, wchar_t const* s2) {
|
|
|
|
int diff;
|
|
|
|
do {
|
|
|
|
diff = *s1 - *s2;
|
|
|
|
} while(diff != 0 && *s1 != 0 && *s2 != 0);
|
|
|
|
return diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t count_wide_chars(const wchar_t* str) {
|
|
|
|
size_t len = 0;
|
|
|
|
while (str[len] != 0) len++;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool wchar_to_ansi(char* out, const wchar_t* str, size_t len) {
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
|
|
wchar_t ch = *str++;
|
|
|
|
if (ch < 0 || ch > 0x7F) {
|
|
|
|
*out++ = 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*out++ = ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
*out++ = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-07-30 05:15:11 +00:00
|
|
|
static int cmdline_to_argv8(const wchar_t *cmd, char **argv);
|
|
|
|
|
2022-06-27 02:04:46 +00:00
|
|
|
static char **get_command_args(int *argc_ptr) {
|
2022-07-30 05:15:11 +00:00
|
|
|
static char *argv_buffer[CMDLINE_ARGV_MAX];
|
|
|
|
// That's right, that's where windows hid the command line
|
|
|
|
TEB *teb = (TEB *)__readgsqword(offsetof(NT_TIB, Self));
|
|
|
|
PEB *peb = teb->ProcessEnvironmentBlock;
|
|
|
|
RTL_USER_PROCESS_PARAMETERS *params = peb->ProcessParameters;
|
|
|
|
UNICODE_STRING command_line_str = params->CommandLine;
|
|
|
|
wchar_t *cmdline = command_line_str.Buffer;
|
|
|
|
// Now we can do the actual job
|
|
|
|
*argc_ptr = cmdline_to_argv8(cmdline, argv_buffer);
|
|
|
|
return argv_buffer;
|
|
|
|
}
|
2022-06-27 02:04:46 +00:00
|
|
|
|
2022-07-30 05:15:11 +00:00
|
|
|
// https://github.com/skeeto/scratch/blob/master/misc/cmdline.c#L27
|
|
|
|
static int cmdline_to_argv8(const wchar_t *cmd, char **argv) {
|
|
|
|
int argc = 1; // worst case: argv[0] is an empty string
|
|
|
|
int state = 6; // special argv[0] state
|
|
|
|
int slash = 0;
|
|
|
|
char *buf = (char *)(argv + 16384); // second half: byte buffer
|
|
|
|
|
|
|
|
argv[0] = buf;
|
|
|
|
while (*cmd) {
|
|
|
|
int c = *cmd++;
|
|
|
|
if (c>>10 == 0x36 && *cmd>>10 == 0x37) { // surrogates?
|
|
|
|
c = 0x10000 + ((c - 0xd800)<<10) + (*cmd++ - 0xdc00);
|
|
|
|
}
|
2022-06-27 02:04:46 +00:00
|
|
|
|
2022-07-30 05:15:11 +00:00
|
|
|
switch (state) {
|
|
|
|
case 0: switch (c) { // outside token
|
|
|
|
case 0x09:
|
|
|
|
case 0x20: continue;
|
|
|
|
case 0x22: argv[argc++] = buf;
|
|
|
|
state = 2;
|
|
|
|
continue;
|
|
|
|
case 0x5c: argv[argc++] = buf;
|
|
|
|
slash = 1;
|
|
|
|
state = 3;
|
|
|
|
break;
|
|
|
|
default : argv[argc++] = buf;
|
|
|
|
state = 1;
|
|
|
|
} break;
|
|
|
|
case 1: switch (c) { // inside unquoted token
|
|
|
|
case 0x09:
|
|
|
|
case 0x20: *buf++ = 0;
|
|
|
|
state = 0;
|
|
|
|
continue;
|
|
|
|
case 0x22: state = 2;
|
|
|
|
continue;
|
|
|
|
case 0x5c: slash = 1;
|
|
|
|
state = 3;
|
|
|
|
break;
|
|
|
|
} break;
|
|
|
|
case 2: switch (c) { // inside quoted token
|
|
|
|
case 0x22: state = 5;
|
|
|
|
continue;
|
|
|
|
case 0x5c: slash = 1;
|
|
|
|
state = 4;
|
|
|
|
break;
|
|
|
|
} break;
|
|
|
|
case 3:
|
|
|
|
case 4: switch (c) { // backslash sequence
|
|
|
|
case 0x22: buf -= (1 + slash) >> 1;
|
|
|
|
if (slash & 1) {
|
|
|
|
state -= 2;
|
|
|
|
break;
|
|
|
|
} // fallthrough
|
|
|
|
default : cmd--;
|
|
|
|
state -= 2;
|
|
|
|
continue;
|
|
|
|
case 0x5c: slash++;
|
|
|
|
} break;
|
|
|
|
case 5: switch (c) { // quoted token exit
|
|
|
|
default : cmd--;
|
|
|
|
state = 1;
|
|
|
|
continue;
|
|
|
|
case 0x22: state = 1;
|
|
|
|
} break;
|
|
|
|
case 6: switch (c) { // begin argv[0]
|
|
|
|
case 0x09:
|
|
|
|
case 0x20: *buf++ = 0;
|
|
|
|
state = 0;
|
|
|
|
continue;
|
|
|
|
case 0x22: state = 8;
|
|
|
|
continue;
|
|
|
|
default : state = 7;
|
|
|
|
} break;
|
|
|
|
case 7: switch (c) { // unquoted argv[0]
|
|
|
|
case 0x09:
|
|
|
|
case 0x20: *buf++ = 0;
|
|
|
|
state = 0;
|
|
|
|
continue;
|
|
|
|
} break;
|
|
|
|
case 8: switch (c) { // quoted argv[0]
|
|
|
|
case 0x22: *buf++ = 0;
|
|
|
|
state = 0;
|
|
|
|
continue;
|
|
|
|
} break;
|
|
|
|
}
|
2022-06-27 02:04:46 +00:00
|
|
|
|
2022-07-30 05:15:11 +00:00
|
|
|
switch (c & 0x1f0880) { // WTF-8/UTF-8 encoding
|
|
|
|
case 0x00000: *buf++ = 0x00 | ((c >> 0) ); break;
|
|
|
|
case 0x00080: *buf++ = 0xc0 | ((c >> 6) );
|
|
|
|
*buf++ = 0x80 | ((c >> 0) & 63); break;
|
|
|
|
case 0x00800:
|
|
|
|
case 0x00880: *buf++ = 0xe0 | ((c >> 12) );
|
|
|
|
*buf++ = 0x80 | ((c >> 6) & 63);
|
|
|
|
*buf++ = 0x80 | ((c >> 0) & 63); break;
|
|
|
|
default : *buf++ = 0xf0 | ((c >> 18) );
|
|
|
|
*buf++ = 0x80 | ((c >> 12) & 63);
|
|
|
|
*buf++ = 0x80 | ((c >> 6) & 63);
|
|
|
|
*buf++ = 0x80 | ((c >> 0) & 63);
|
|
|
|
}
|
2022-06-27 02:04:46 +00:00
|
|
|
}
|
|
|
|
|
2022-07-30 05:15:11 +00:00
|
|
|
*buf = 0;
|
|
|
|
argv[argc] = 0;
|
|
|
|
return argc;
|
2022-06-27 02:04:46 +00:00
|
|
|
}
|