Last active
June 20, 2024 19:56
-
-
Save jeremyd2019/f1a3aff7a46e953dec38035e87f265c0 to your computer and use it in GitHub Desktop.
exec proper wine based on arch of PE binary
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Register with: | |
* echo :wine:M::MZ::/opt/wine-arch-detector:PO > /proc/sys/fs/binfmt_misc/register | |
*/ | |
#include <errno.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <sys/auxv.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
int main(int argc, char ** argv) | |
{ | |
struct stat st; | |
FILE * fh; | |
unsigned long atexecfd; | |
int lfa; | |
unsigned short machine; | |
unsigned char ub[4]; | |
if (argc < 3) | |
{ | |
fprintf(stderr, "Usage: %s <file> <argv0> ...\n", argv[0]); | |
return 1; | |
} | |
atexecfd = getauxval(AT_EXECFD); | |
if (atexecfd) | |
fh = fdopen(atexecfd, "rb"); | |
else | |
fh = fopen(argv[1], "rb"); | |
if (!fh) | |
{ | |
fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); | |
return 2; | |
} | |
if (fstat(fileno(fh), &st) != 0) | |
{ | |
fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); | |
fclose(fh); | |
return 2; | |
} | |
if (st.st_size < 256) | |
{ | |
fprintf(stderr, "%s: File too small\n", argv[1]); | |
fclose(fh); | |
return 2; | |
} | |
if (fread(ub, 2, 1, fh) != 1) | |
{ | |
fprintf(stderr, "%s: Short read\n", argv[1]); | |
fclose(fh); | |
return 2; | |
} | |
if (ub[0] != 'M' || ub[1] != 'Z') | |
{ | |
fprintf(stderr, "%s: File does not start with MZ\n", argv[1]); | |
fclose(fh); | |
return 2; | |
} | |
if (fseek(fh, 60, SEEK_SET) != 0) | |
{ | |
fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); | |
fclose(fh); | |
return 2; | |
} | |
if (fread(ub, 4, 1, fh) != 1) | |
{ | |
fprintf(stderr, "%s: Short read\n", argv[1]); | |
fclose(fh); | |
return 2; | |
} | |
lfa = (int)((unsigned int)ub[3] << 24 | (unsigned int)ub[2] << 16 | (unsigned int)ub[1] << 8 | ub[0]); | |
if (lfa <= 0 || lfa >= st.st_size) | |
{ | |
fprintf(stderr, "%s: PE header offset out of bounds\n", argv[1]); | |
fclose(fh); | |
return 2; | |
} | |
if (fseek(fh, lfa, SEEK_SET) != 0) | |
{ | |
fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); | |
fclose(fh); | |
return 2; | |
} | |
if (fread(ub, 4, 1, fh) != 1) | |
{ | |
fprintf(stderr, "%s: Short read\n", argv[1]); | |
fclose(fh); | |
return 2; | |
} | |
if (ub[0] != 'P' || ub[1] != 'E' || ub[2] != 0 || ub[3] != 0) | |
{ | |
fprintf(stderr, "%s: PE header not found\n", argv[1]); | |
fclose(fh); | |
return 2; | |
} | |
if (fread(ub, 2, 1, fh) != 1) | |
{ | |
fprintf(stderr, "%s: Short read\n", argv[1]); | |
fclose(fh); | |
return 2; | |
} | |
machine = (unsigned short)ub[1] << 8 | ub[0]; | |
#ifdef _DEBUG | |
printf("%s: machine 0x%04hx\n", argv[1], machine); | |
#endif | |
fclose(fh); | |
/* TODO: should I register without P flag and replace argv[0] instead? */ | |
argv[2] = argv[1]; | |
switch (machine) | |
{ | |
case 0x014c: | |
case 0x8664: | |
argv[1] = "/usr/bin/wine"; | |
break; | |
case 0xaa64: | |
argv[1] = "/usr/bin/wine-arm64"; | |
break; | |
default: | |
fprintf(stderr, "%s: Unhandled machine type in PE file %s: 0x%04hx\n", argv[0], argv[1], machine); | |
return 3; | |
} | |
execv(argv[1], &argv[1]); | |
fprintf(stderr, "%s: Error execing %s: %s\n", argv[0], argv[1], strerror(errno)); | |
return 5; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment