Skip to content

Instantly share code, notes, and snippets.

@jeremyd2019
Last active June 20, 2024 19:56
Show Gist options
  • Save jeremyd2019/f1a3aff7a46e953dec38035e87f265c0 to your computer and use it in GitHub Desktop.
Save jeremyd2019/f1a3aff7a46e953dec38035e87f265c0 to your computer and use it in GitHub Desktop.
exec proper wine based on arch of PE binary
/* 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