* Detect architecture from ELF header (e_machine field at bytes 18-19). * Falls back to filename-based detection if not a valid ELF.
(filePath: string)
| 397 | * Falls back to filename-based detection if not a valid ELF. |
| 398 | */ |
| 399 | function detectArch(filePath: string): string | null { |
| 400 | try { |
| 401 | const fd = fs.openSync(filePath, "r"); |
| 402 | try { |
| 403 | const header = Buffer.alloc(20); |
| 404 | fs.readSync(fd, header, 0, 20, 0); |
| 405 | |
| 406 | // Verify ELF magic: 0x7f 'E' 'L' 'F' |
| 407 | if ( |
| 408 | header[0] !== 0x7f || |
| 409 | header[1] !== 0x45 || |
| 410 | header[2] !== 0x4c || |
| 411 | header[3] !== 0x46 |
| 412 | ) { |
| 413 | return detectArchFromFilename(filePath); |
| 414 | } |
| 415 | |
| 416 | // e_machine at offset 18 (little-endian uint16) |
| 417 | const eMachine = header.readUInt16LE(18); |
| 418 | switch (eMachine) { |
| 419 | case 0x28: |
| 420 | return "armeabi-v7a"; // EM_ARM |
| 421 | case 0xb7: |
| 422 | return "arm64-v8a"; // EM_AARCH64 |
| 423 | case 0x03: |
| 424 | return "x86"; // EM_386 |
| 425 | case 0x3e: |
| 426 | return "x86_64"; // EM_X86_64 |
| 427 | default: |
| 428 | return detectArchFromFilename(filePath); |
| 429 | } |
| 430 | } finally { |
| 431 | fs.closeSync(fd); |
| 432 | } |
| 433 | } catch { |
| 434 | return detectArchFromFilename(filePath); |
| 435 | } |
| 436 | } |
| 437 | |
| 438 | /** |
| 439 | * Fallback: detect architecture from gadget filename. |
no test coverage detected