#!/bin/awk -f # # Determine the subsystem of a PE32 executable. # # Copyright © 2022 Nick Bowler # # License WTFPL2: Do What The Fuck You Want To Public License, version 2. # This is free software: you are free to do what the fuck you want to. # There is NO WARRANTY, to the extent permitted by law. BEGIN { filename = ARGV[1]; subsys = "unknown"; endian = "unknown"; if (!filename) { exit(1); } probe_dumper(filename); od_read("0"); if ($2 == "055115") { endian = "little"; } else if ($2 == "046532") { endian = "big"; } else { exit(1); } od_read("74"); val = 65536*od_decode($3) + od_decode($2); pe_offset = sprintf("%o", val); pe32_offset = sprintf("%o", val+24); subsys_offset = sprintf("%o", val+24+68); od_read(pe_offset); if ($2 != "042520" || $3 != "000000") { # bad PE header exit(1); } od_read(pe32_offset); if ($2 != "000413" && $2 != "001013") { # bad PE32(+) header exit(1); } od_read(subsys_offset); subsys = od_decode($2); if (subsys == 2) subsys = "gui"; else if (subsys == 3) subsys = "console"; else subsys = "unknown (" subsys ")"; exit(0); } END { print subsys } function probe_dumper(filename) { (cmd = "od " filename " +10 2>/dev/null") | getline close(cmd) sub(/^0*/, "", $1); if ($1 == 10) { dumper_style = "od_traditional"; return; } (cmd = "od -j010 " filename " 2>/dev/null") | getline close(cmd) sub(/^0*/, "", $1); if ($1 == 10) { dumper_style = "od_posix"; return; } exit(1); } function od_read(offset, cmd) { if (dumper_style == "od_traditional") { cmd = "od " filename " +" offset; } else if (dumper_style == "od_posix") { cmd = "od -j0" offset " " filename; } cmd | getline close(cmd); if (endian == "big") { $2 = od_bswap($2); $3 = od_bswap($3); } } # Byte-swap one of the 2-byte blocks of octal digits emitted by od. function od_bswap(word, i, digits, carry) { for (i = 0; i < 6; i++) { digits[i] = substr(word, i+1, 1); } # suss out the first byte by adjusting the first 4 digits left by 1 bit if (carry = (digits[3] >= 4)) digits[3] -= 4; for (i = 2; i >= 0; i--) { if (carry = ( (digits[i] = digits[i]*2 + carry) >= 8 )) digits[i] -= 8; } # now munge the second byte by adjusting the last 3 digits right 1 bit carry = 0; for (i = 3; i < 6; i++) { carry = (digits[i] += 8*carry) % 2; digits[i] = int(digits[i] / 2); } # and put the leftover bit in place digits[0] += 4*carry; return digits[3] digits[4] digits[5] digits[0] digits[1] digits[2]; } # Parse a string of octal digits into a number. function od_decode(word, result) { result = 0; while (word) { result = 8*result + substr(word, 1, 1); word = substr(word, 2); } return result; }