mirror of
https://github.com/grub4dos/ntloader.git
synced 2025-05-08 19:51:14 +08:00
add bmtool
This commit is contained in:
parent
521dd72ac7
commit
1ba67d92ac
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -47,6 +47,9 @@ jobs:
|
|||||||
- name: Build fsuuid.exe
|
- name: Build fsuuid.exe
|
||||||
run: |
|
run: |
|
||||||
make fsuuid.exe
|
make fsuuid.exe
|
||||||
|
- name: Build bmtool.exe
|
||||||
|
run: |
|
||||||
|
make bmtool.exe
|
||||||
- name: Copy files
|
- name: Copy files
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
@ -55,6 +58,7 @@ jobs:
|
|||||||
cp ntloader.arm64 build/
|
cp ntloader.arm64 build/
|
||||||
cp initrd.cpio build/
|
cp initrd.cpio build/
|
||||||
cp fsuuid.exe build/
|
cp fsuuid.exe build/
|
||||||
|
cp bmtool.exe build/
|
||||||
cp mkinitrd.exe build/
|
cp mkinitrd.exe build/
|
||||||
cp utils/bcd.bat build/
|
cp utils/bcd.bat build/
|
||||||
- name: Download README.pdf
|
- name: Download README.pdf
|
||||||
|
@ -298,6 +298,9 @@ mkinitrd.exe rootfs initrd.cpio
|
|||||||
find * | cpio -o -H newc > ../initrd.cpio
|
find * | cpio -o -H newc > ../initrd.cpio
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### bmtool
|
||||||
|
`bmtool` is a program for extracting bootmgr.exe from bootmgr.
|
||||||
|
|
||||||
### bcd.bat
|
### bcd.bat
|
||||||
`bcd.bat` is a batch script to create the BCD file.
|
`bcd.bat` is a batch script to create the BCD file.
|
||||||
Do not edit it unless you know how NTloader works.
|
Do not edit it unless you know how NTloader works.
|
||||||
@ -323,6 +326,12 @@ make fsuuid
|
|||||||
make fsuuid.exe
|
make fsuuid.exe
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Compile bmtool
|
||||||
|
```
|
||||||
|
make bmtool
|
||||||
|
make bmtool.exe
|
||||||
|
```
|
||||||
|
|
||||||
### Compile mkinitrd
|
### Compile mkinitrd
|
||||||
```
|
```
|
||||||
make mkinitrd
|
make mkinitrd
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
#define assert(x) \
|
#define assert(x) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
if (DEBUG && ! (x)) \
|
if (! (x)) \
|
||||||
{ \
|
{ \
|
||||||
die ("Assertion failed at %s line %d: %s\n", \
|
die ("Assertion failed at %s line %d: %s\n", \
|
||||||
__FILE__, __LINE__, #x); \
|
__FILE__, __LINE__, #x); \
|
||||||
|
115
include/huffman.h
Normal file
115
include/huffman.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#ifndef _HUFFMAN_H
|
||||||
|
#define _HUFFMAN_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* Huffman alphabets
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/** Maximum length of a Huffman symbol (in bits) */
|
||||||
|
#define HUFFMAN_BITS 16
|
||||||
|
|
||||||
|
/** Raw huffman symbol */
|
||||||
|
typedef uint16_t huffman_raw_symbol_t;
|
||||||
|
|
||||||
|
/** Quick lookup length for a Huffman symbol (in bits)
|
||||||
|
*
|
||||||
|
* This is a policy decision.
|
||||||
|
*/
|
||||||
|
#define HUFFMAN_QL_BITS 7
|
||||||
|
|
||||||
|
/** Quick lookup shift */
|
||||||
|
#define HUFFMAN_QL_SHIFT (HUFFMAN_BITS - HUFFMAN_QL_BITS)
|
||||||
|
|
||||||
|
/** A Huffman-coded set of symbols of a given length */
|
||||||
|
struct huffman_symbols
|
||||||
|
{
|
||||||
|
/** Length of Huffman-coded symbols (in bits) */
|
||||||
|
uint8_t bits;
|
||||||
|
/** Shift to normalise symbols of this length to HUFFMAN_BITS bits */
|
||||||
|
uint8_t shift;
|
||||||
|
/** Number of Huffman-coded symbols having this length */
|
||||||
|
uint16_t freq;
|
||||||
|
/** First symbol of this length (normalised to HUFFMAN_BITS bits)
|
||||||
|
*
|
||||||
|
* Stored as a 32-bit value to allow the value
|
||||||
|
* (1<<HUFFMAN_BITS) to be used for empty sets of symbols
|
||||||
|
* longer than the maximum utilised length.
|
||||||
|
*/
|
||||||
|
uint32_t start;
|
||||||
|
/** Raw symbols having this length */
|
||||||
|
huffman_raw_symbol_t *raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A Huffman-coded alphabet */
|
||||||
|
struct huffman_alphabet
|
||||||
|
{
|
||||||
|
/** Huffman-coded symbol set for each length */
|
||||||
|
struct huffman_symbols huf[HUFFMAN_BITS];
|
||||||
|
/** Quick lookup table */
|
||||||
|
uint8_t lookup[1 << HUFFMAN_QL_BITS];
|
||||||
|
/** Raw symbols
|
||||||
|
*
|
||||||
|
* Ordered by Huffman-coded symbol length, then by symbol
|
||||||
|
* value. This field has a variable length.
|
||||||
|
*/
|
||||||
|
huffman_raw_symbol_t raw[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Huffman symbol length
|
||||||
|
*
|
||||||
|
* @v sym Huffman symbol set
|
||||||
|
* @ret len Length (in bits)
|
||||||
|
*/
|
||||||
|
static inline __attribute__ ((always_inline)) unsigned int
|
||||||
|
huffman_len (struct huffman_symbols *sym)
|
||||||
|
{
|
||||||
|
|
||||||
|
return sym->bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Huffman symbol value
|
||||||
|
*
|
||||||
|
* @v sym Huffman symbol set
|
||||||
|
* @v huf Raw input value (normalised to HUFFMAN_BITS bits)
|
||||||
|
* @ret raw Raw symbol value
|
||||||
|
*/
|
||||||
|
static inline __attribute__ ((always_inline)) huffman_raw_symbol_t
|
||||||
|
huffman_raw (struct huffman_symbols *sym, unsigned int huf)
|
||||||
|
{
|
||||||
|
|
||||||
|
return sym->raw[ huf >> sym->shift ];
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int
|
||||||
|
huffman_alphabet (struct huffman_alphabet *alphabet,
|
||||||
|
uint8_t *lengths, unsigned int count);
|
||||||
|
extern struct huffman_symbols *
|
||||||
|
huffman_sym (struct huffman_alphabet *alphabet, unsigned int huf);
|
||||||
|
|
||||||
|
#endif /* _HUFFMAN_H */
|
48
include/lznt1.h
Normal file
48
include/lznt1.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef _LZNT1_H
|
||||||
|
#define _LZNT1_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* LZNT1 decompression
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/** Extract LZNT1 block length */
|
||||||
|
#define LZNT1_BLOCK_LEN(header) (((header) & 0x0fff) + 1)
|
||||||
|
|
||||||
|
/** Determine if LZNT1 block is compressed */
|
||||||
|
#define LZNT1_BLOCK_COMPRESSED(header) ((header) & 0x8000)
|
||||||
|
|
||||||
|
/** Extract LZNT1 compressed value length */
|
||||||
|
#define LZNT1_VALUE_LEN(tuple, split) \
|
||||||
|
(((tuple) & ((1 << (split)) - 1)) + 3)
|
||||||
|
|
||||||
|
/** Extract LZNT1 compressed value offset */
|
||||||
|
#define LZNT1_VALUE_OFFSET(tuple, split) (((tuple) >> split) + 1)
|
||||||
|
|
||||||
|
extern ssize_t
|
||||||
|
lznt1_decompress (const void *data, size_t len, void *buf);
|
||||||
|
|
||||||
|
#endif /* _LZNT1_H */
|
96
include/xca.h
Normal file
96
include/xca.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#ifndef _XCA_H
|
||||||
|
#define _XCA_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* Xpress Compression Algorithm (MS-XCA) decompression
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "huffman.h"
|
||||||
|
|
||||||
|
/** Number of XCA codes */
|
||||||
|
#define XCA_CODES 512
|
||||||
|
|
||||||
|
/** XCA decompressor */
|
||||||
|
struct xca
|
||||||
|
{
|
||||||
|
/** Huffman alphabet */
|
||||||
|
struct huffman_alphabet alphabet;
|
||||||
|
/** Raw symbols
|
||||||
|
*
|
||||||
|
* Must immediately follow the Huffman alphabet.
|
||||||
|
*/
|
||||||
|
huffman_raw_symbol_t raw[XCA_CODES];
|
||||||
|
/** Code lengths */
|
||||||
|
uint8_t lengths[XCA_CODES];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** XCA symbol Huffman lengths table */
|
||||||
|
struct xca_huf_len
|
||||||
|
{
|
||||||
|
/** Lengths of each symbol */
|
||||||
|
uint8_t nibbles[XCA_CODES / 2];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract Huffman-coded length of a raw symbol
|
||||||
|
*
|
||||||
|
* @v lengths Huffman lengths table
|
||||||
|
* @v symbol Raw symbol
|
||||||
|
* @ret len Huffman-coded length
|
||||||
|
*/
|
||||||
|
static inline unsigned int
|
||||||
|
xca_huf_len (const struct xca_huf_len *lengths, unsigned int symbol)
|
||||||
|
{
|
||||||
|
return (((lengths->nibbles[ symbol / 2 ]) >>
|
||||||
|
(4 * (symbol % 2))) & 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get word from source data stream */
|
||||||
|
#define XCA_GET16(src) \
|
||||||
|
({ \
|
||||||
|
const uint16_t *src16 = src; \
|
||||||
|
src += sizeof (*src16); \
|
||||||
|
*src16; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/** Get byte from source data stream */
|
||||||
|
#define XCA_GET8(src) \
|
||||||
|
({ \
|
||||||
|
const uint8_t *src8 = src; \
|
||||||
|
src += sizeof (*src8); \
|
||||||
|
*src8; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/** XCA source data stream end marker */
|
||||||
|
#define XCA_END_MARKER 256
|
||||||
|
|
||||||
|
/** XCA block size */
|
||||||
|
#define XCA_BLOCK_SIZE (64 * 1024)
|
||||||
|
|
||||||
|
extern ssize_t
|
||||||
|
xca_decompress (const void *data, size_t len, void *buf);
|
||||||
|
|
||||||
|
#endif /* _XCA_H */
|
@ -7,5 +7,9 @@ OBJECTS += libnt/vdisk.o
|
|||||||
|
|
||||||
OBJECTS += libnt/peloader.o
|
OBJECTS += libnt/peloader.o
|
||||||
|
|
||||||
|
# OBJECTS += libnt/huffman.c
|
||||||
|
# OBJECTS += libnt/lznt1.c
|
||||||
|
# OBJECTS += libnt/xca.c
|
||||||
|
|
||||||
RM_FILES += libnt/*.s libnt/*.o
|
RM_FILES += libnt/*.s libnt/*.o
|
||||||
|
|
||||||
|
234
libnt/huffman.c
Normal file
234
libnt/huffman.c
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* Huffman alphabets
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "huffman.h"
|
||||||
|
|
||||||
|
#ifdef NTLOADER_UTIL
|
||||||
|
#define DBG(...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
fprintf (stderr, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transcribe binary value (for debugging)
|
||||||
|
*
|
||||||
|
* @v value Value
|
||||||
|
* @v bits Length of value (in bits)
|
||||||
|
* @ret string Transcribed value
|
||||||
|
*/
|
||||||
|
static const char *
|
||||||
|
huffman_bin (unsigned long value, unsigned int bits)
|
||||||
|
{
|
||||||
|
static char buf[(8 * sizeof (value)) + 1 /* NUL */];
|
||||||
|
char *out = buf;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
assert (bits < sizeof (buf));
|
||||||
|
|
||||||
|
/* Transcribe value */
|
||||||
|
while (bits--)
|
||||||
|
*(out++) = ((value & (1 << bits)) ? '1' : '0');
|
||||||
|
*out = '\0';
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump Huffman alphabet (for debugging)
|
||||||
|
*
|
||||||
|
* @v alphabet Huffman alphabet
|
||||||
|
*/
|
||||||
|
static void __attribute__ ((unused))
|
||||||
|
huffman_dump_alphabet (struct huffman_alphabet *alphabet)
|
||||||
|
{
|
||||||
|
struct huffman_symbols *sym;
|
||||||
|
unsigned int bits;
|
||||||
|
unsigned int huf;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/* Dump symbol table for each utilised length */
|
||||||
|
for (bits = 1; bits <= (sizeof (alphabet->huf) /
|
||||||
|
sizeof (alphabet->huf[0])); bits++)
|
||||||
|
{
|
||||||
|
sym = &alphabet->huf[bits - 1];
|
||||||
|
if (sym->freq == 0)
|
||||||
|
continue;
|
||||||
|
huf = (sym->start >> sym->shift);
|
||||||
|
DBG ("Huffman length %d start \"%s\" freq %d:", bits,
|
||||||
|
huffman_bin (huf, sym->bits), sym->freq);
|
||||||
|
for (i = 0; i < sym->freq; i++)
|
||||||
|
{
|
||||||
|
DBG (" %03x", sym->raw[huf + i]);
|
||||||
|
}
|
||||||
|
DBG ("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dump quick lookup table */
|
||||||
|
DBG ("Huffman quick lookup:");
|
||||||
|
for (i = 0; i < (sizeof (alphabet->lookup) /
|
||||||
|
sizeof (alphabet->lookup[0])); i++)
|
||||||
|
{
|
||||||
|
DBG (" %d", (alphabet->lookup[i] + 1));
|
||||||
|
}
|
||||||
|
DBG ("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct Huffman alphabet
|
||||||
|
*
|
||||||
|
* @v alphabet Huffman alphabet
|
||||||
|
* @v lengths Symbol length table
|
||||||
|
* @v count Number of symbols
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
int huffman_alphabet (struct huffman_alphabet *alphabet,
|
||||||
|
uint8_t *lengths, unsigned int count)
|
||||||
|
{
|
||||||
|
struct huffman_symbols *sym;
|
||||||
|
unsigned int huf;
|
||||||
|
unsigned int cum_freq;
|
||||||
|
unsigned int bits;
|
||||||
|
unsigned int raw;
|
||||||
|
unsigned int adjustment;
|
||||||
|
unsigned int prefix;
|
||||||
|
int empty;
|
||||||
|
int complete;
|
||||||
|
|
||||||
|
/* Clear symbol table */
|
||||||
|
memset (alphabet->huf, 0, sizeof (alphabet->huf));
|
||||||
|
|
||||||
|
/* Count number of symbols with each Huffman-coded length */
|
||||||
|
empty = 1;
|
||||||
|
for (raw = 0; raw < count; raw++)
|
||||||
|
{
|
||||||
|
bits = lengths[raw];
|
||||||
|
if (bits)
|
||||||
|
{
|
||||||
|
alphabet->huf[bits - 1].freq++;
|
||||||
|
empty = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In the degenerate case of having no symbols (i.e. an unused
|
||||||
|
* alphabet), generate a trivial alphabet with exactly two
|
||||||
|
* single-bit codes. This allows callers to avoid having to
|
||||||
|
* check for this special case.
|
||||||
|
*/
|
||||||
|
if (empty)
|
||||||
|
alphabet->huf[0].freq = 2;
|
||||||
|
|
||||||
|
/* Populate Huffman-coded symbol table */
|
||||||
|
huf = 0;
|
||||||
|
cum_freq = 0;
|
||||||
|
for (bits = 1; bits <= (sizeof (alphabet->huf) /
|
||||||
|
sizeof (alphabet->huf[0])); bits++)
|
||||||
|
{
|
||||||
|
sym = &alphabet->huf[ bits - 1 ];
|
||||||
|
sym->bits = bits;
|
||||||
|
sym->shift = (HUFFMAN_BITS - bits);
|
||||||
|
sym->start = (huf << sym->shift);
|
||||||
|
sym->raw = &alphabet->raw[cum_freq];
|
||||||
|
huf += sym->freq;
|
||||||
|
if (huf > (1U << bits))
|
||||||
|
{
|
||||||
|
DBG ("Huffman alphabet has too many symbols with "
|
||||||
|
"lengths <=%d\n", bits);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
huf <<= 1;
|
||||||
|
cum_freq += sym->freq;
|
||||||
|
}
|
||||||
|
complete = (huf == (1U << bits));
|
||||||
|
|
||||||
|
/* Populate raw symbol table */
|
||||||
|
for (raw = 0; raw < count; raw++)
|
||||||
|
{
|
||||||
|
bits = lengths[raw];
|
||||||
|
if (bits)
|
||||||
|
{
|
||||||
|
sym = &alphabet->huf[ bits - 1 ];
|
||||||
|
*(sym->raw++) = raw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust Huffman-coded symbol table raw pointers and populate
|
||||||
|
* quick lookup table.
|
||||||
|
*/
|
||||||
|
for (bits = 1; bits <= (sizeof (alphabet->huf) /
|
||||||
|
sizeof (alphabet->huf[0])); bits++)
|
||||||
|
{
|
||||||
|
sym = &alphabet->huf[ bits - 1 ];
|
||||||
|
|
||||||
|
/* Adjust raw pointer */
|
||||||
|
sym->raw -= sym->freq; /* Reset to first symbol */
|
||||||
|
adjustment = (sym->start >> sym->shift);
|
||||||
|
sym->raw -= adjustment; /* Adjust for quick indexing */
|
||||||
|
|
||||||
|
/* Populate quick lookup table */
|
||||||
|
for (prefix = (sym->start >> HUFFMAN_QL_SHIFT);
|
||||||
|
prefix < (1 << HUFFMAN_QL_BITS); prefix++)
|
||||||
|
{
|
||||||
|
alphabet->lookup[prefix] = (bits - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that there are no invalid codes */
|
||||||
|
if (! complete)
|
||||||
|
{
|
||||||
|
DBG ("Huffman alphabet is incomplete\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Huffman symbol set
|
||||||
|
*
|
||||||
|
* @v alphabet Huffman alphabet
|
||||||
|
* @v huf Raw input value (normalised to HUFFMAN_BITS bits)
|
||||||
|
* @ret sym Huffman symbol set
|
||||||
|
*/
|
||||||
|
struct huffman_symbols *
|
||||||
|
huffman_sym (struct huffman_alphabet *alphabet,
|
||||||
|
unsigned int huf)
|
||||||
|
{
|
||||||
|
struct huffman_symbols *sym;
|
||||||
|
unsigned int lookup_index;
|
||||||
|
|
||||||
|
/* Find symbol set for this length */
|
||||||
|
lookup_index = (huf >> HUFFMAN_QL_SHIFT);
|
||||||
|
sym = &alphabet->huf[alphabet->lookup[lookup_index]];
|
||||||
|
while (huf < sym->start)
|
||||||
|
sym--;
|
||||||
|
return sym;
|
||||||
|
}
|
199
libnt/lznt1.c
Normal file
199
libnt/lznt1.c
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* LZNT1 decompression
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "lznt1.h"
|
||||||
|
|
||||||
|
#ifdef NTLOADER_UTIL
|
||||||
|
#define DBG(...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
fprintf (stderr, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DBG2(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompress LZNT1-compressed data block
|
||||||
|
*
|
||||||
|
* @v data Compressed data
|
||||||
|
* @v limit Length of compressed data up to end of block
|
||||||
|
* @v offset Starting offset within compressed data
|
||||||
|
* @v block Decompression buffer for this block, or NULL
|
||||||
|
* @ret out_len Length of decompressed block, or negative error
|
||||||
|
*/
|
||||||
|
static ssize_t
|
||||||
|
lznt1_block (const void *data, size_t limit, size_t offset,
|
||||||
|
void *block)
|
||||||
|
{
|
||||||
|
const uint16_t *tuple;
|
||||||
|
const uint8_t *copy_src;
|
||||||
|
uint8_t *copy_dest = block;
|
||||||
|
size_t copy_len;
|
||||||
|
size_t block_out_len = 0;
|
||||||
|
unsigned int split = 12;
|
||||||
|
unsigned int next_threshold = 16;
|
||||||
|
unsigned int tag_bit = 0;
|
||||||
|
unsigned int tag = 0;
|
||||||
|
|
||||||
|
while (offset != limit)
|
||||||
|
{
|
||||||
|
/* Extract tag */
|
||||||
|
if (tag_bit == 0)
|
||||||
|
{
|
||||||
|
tag = *((uint8_t *) (data + offset));
|
||||||
|
offset++;
|
||||||
|
if (offset == limit)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate copy source and length */
|
||||||
|
if (tag & 1)
|
||||||
|
{
|
||||||
|
/* Compressed value */
|
||||||
|
if (offset + sizeof (*tuple) > limit)
|
||||||
|
{
|
||||||
|
DBG ("LZNT1 compressed value overrun at %#zx\n",
|
||||||
|
offset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
tuple = (data + offset);
|
||||||
|
offset += sizeof (*tuple);
|
||||||
|
copy_len = LZNT1_VALUE_LEN (*tuple, split);
|
||||||
|
block_out_len += copy_len;
|
||||||
|
if (copy_dest)
|
||||||
|
{
|
||||||
|
copy_src = (copy_dest -
|
||||||
|
LZNT1_VALUE_OFFSET (*tuple, split));
|
||||||
|
while (copy_len--)
|
||||||
|
*(copy_dest++) = *(copy_src++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Uncompressed value */
|
||||||
|
copy_src = (data + offset);
|
||||||
|
if (copy_dest)
|
||||||
|
*(copy_dest++) = *copy_src;
|
||||||
|
offset++;
|
||||||
|
block_out_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update split, if applicable */
|
||||||
|
while (block_out_len > next_threshold)
|
||||||
|
{
|
||||||
|
split--;
|
||||||
|
next_threshold <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move to next value */
|
||||||
|
tag >>= 1;
|
||||||
|
tag_bit = ((tag_bit + 1) % 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return block_out_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompress LZNT1-compressed data
|
||||||
|
*
|
||||||
|
* @v data Compressed data
|
||||||
|
* @v len Length of compressed data
|
||||||
|
* @v buf Decompression buffer, or NULL
|
||||||
|
* @ret out_len Length of decompressed data, or negative error
|
||||||
|
*/
|
||||||
|
ssize_t lznt1_decompress (const void *data, size_t len, void *buf)
|
||||||
|
{
|
||||||
|
const uint16_t *header;
|
||||||
|
const uint8_t *end;
|
||||||
|
size_t offset = 0;
|
||||||
|
ssize_t out_len = 0;
|
||||||
|
size_t block_len;
|
||||||
|
size_t limit;
|
||||||
|
void *block;
|
||||||
|
ssize_t block_out_len;
|
||||||
|
|
||||||
|
while (offset != len)
|
||||||
|
{
|
||||||
|
/* Check for end marker */
|
||||||
|
if ((offset + sizeof (*end)) == len)
|
||||||
|
{
|
||||||
|
end = (data + offset);
|
||||||
|
if (*end == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract block header */
|
||||||
|
if ((offset + sizeof (*header)) > len)
|
||||||
|
{
|
||||||
|
DBG ("LZNT1 block header overrun at %#zx\n", offset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
header = (data + offset);
|
||||||
|
offset += sizeof (*header);
|
||||||
|
|
||||||
|
/* Process block */
|
||||||
|
block_len = LZNT1_BLOCK_LEN (*header);
|
||||||
|
if (LZNT1_BLOCK_COMPRESSED (*header))
|
||||||
|
{
|
||||||
|
/* Compressed block */
|
||||||
|
DBG2 ("LZNT1 compressed block %#zx+%#zx\n",
|
||||||
|
offset, block_len);
|
||||||
|
limit = (offset + block_len);
|
||||||
|
block = (buf ? (buf + out_len) : NULL);
|
||||||
|
block_out_len = lznt1_block (data, limit, offset,
|
||||||
|
block);
|
||||||
|
if (block_out_len < 0)
|
||||||
|
return block_out_len;
|
||||||
|
offset += block_len;
|
||||||
|
out_len += block_out_len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Uncompressed block */
|
||||||
|
if ((offset + block_len) > len)
|
||||||
|
{
|
||||||
|
DBG ("LZNT1 uncompressed block overrun at "
|
||||||
|
"%#zx+%#zx\n", offset, block_len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
DBG2 ("LZNT1 uncompressed block %#zx+%#zx\n",
|
||||||
|
offset, block_len);
|
||||||
|
if (buf)
|
||||||
|
{
|
||||||
|
memcpy (buf + out_len, data + offset, block_len);
|
||||||
|
}
|
||||||
|
offset += block_len;
|
||||||
|
out_len += block_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out_len;
|
||||||
|
}
|
182
libnt/xca.c
Normal file
182
libnt/xca.c
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* Xpress Compression Algorithm (MS-XCA) decompression
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "huffman.h"
|
||||||
|
#include "xca.h"
|
||||||
|
|
||||||
|
#ifdef NTLOADER_UTIL
|
||||||
|
#define DBG(...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
fprintf (stderr, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompress XCA-compressed data
|
||||||
|
*
|
||||||
|
* @v data Compressed data
|
||||||
|
* @v len Length of compressed data
|
||||||
|
* @v buf Decompression buffer, or NULL
|
||||||
|
* @ret out_len Length of decompressed data, or negative error
|
||||||
|
*/
|
||||||
|
ssize_t xca_decompress (const void *data, size_t len, void *buf)
|
||||||
|
{
|
||||||
|
const void *src = data;
|
||||||
|
const void *end = (src + len);
|
||||||
|
uint8_t *out = buf;
|
||||||
|
size_t out_len = 0;
|
||||||
|
size_t out_len_threshold = 0;
|
||||||
|
const struct xca_huf_len *lengths;
|
||||||
|
struct xca xca;
|
||||||
|
uint32_t accum = 0;
|
||||||
|
int extra_bits = 0;
|
||||||
|
unsigned int huf;
|
||||||
|
struct huffman_symbols *sym;
|
||||||
|
unsigned int raw;
|
||||||
|
unsigned int match_len;
|
||||||
|
unsigned int match_offset_bits;
|
||||||
|
unsigned int match_offset;
|
||||||
|
const uint8_t *copy;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Process data stream */
|
||||||
|
while (src < end)
|
||||||
|
{
|
||||||
|
/* (Re)initialise decompressor if applicable */
|
||||||
|
if (out_len >= out_len_threshold)
|
||||||
|
{
|
||||||
|
/* Construct symbol lengths */
|
||||||
|
lengths = src;
|
||||||
|
src += sizeof (*lengths);
|
||||||
|
if (src > end)
|
||||||
|
{
|
||||||
|
DBG ("XCA too short to hold Huffman lengths "
|
||||||
|
"table at input offset %#zx\n", src - data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (raw = 0; raw < XCA_CODES; raw++)
|
||||||
|
xca.lengths[raw] = xca_huf_len (lengths, raw);
|
||||||
|
|
||||||
|
/* Construct Huffman alphabet */
|
||||||
|
if ((rc = huffman_alphabet (&xca.alphabet,
|
||||||
|
xca.lengths,
|
||||||
|
XCA_CODES)) != 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Initialise state */
|
||||||
|
accum = XCA_GET16 (src);
|
||||||
|
accum <<= 16;
|
||||||
|
accum |= XCA_GET16 (src);
|
||||||
|
extra_bits = 16;
|
||||||
|
|
||||||
|
/* Determine next threshold */
|
||||||
|
out_len_threshold = (out_len + XCA_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine symbol */
|
||||||
|
huf = (accum >> (32 - HUFFMAN_BITS));
|
||||||
|
sym = huffman_sym (&xca.alphabet, huf);
|
||||||
|
raw = huffman_raw (sym, huf);
|
||||||
|
accum <<= huffman_len (sym);
|
||||||
|
extra_bits -= huffman_len (sym);
|
||||||
|
if (extra_bits < 0)
|
||||||
|
{
|
||||||
|
accum |= (XCA_GET16 (src) << (-extra_bits));
|
||||||
|
extra_bits += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process symbol */
|
||||||
|
if (raw < XCA_END_MARKER)
|
||||||
|
{
|
||||||
|
/* Literal symbol - add to output stream */
|
||||||
|
if (buf)
|
||||||
|
*(out++) = raw;
|
||||||
|
out_len++;
|
||||||
|
}
|
||||||
|
else if ((raw == XCA_END_MARKER) && (src >= (end - 1)))
|
||||||
|
{
|
||||||
|
/* End marker symbol */
|
||||||
|
return out_len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* LZ77 match symbol */
|
||||||
|
raw -= XCA_END_MARKER;
|
||||||
|
match_offset_bits = (raw >> 4);
|
||||||
|
match_len = (raw & 0x0f);
|
||||||
|
if (match_len == 0x0f)
|
||||||
|
{
|
||||||
|
match_len = XCA_GET8 (src);
|
||||||
|
if (match_len == 0xff)
|
||||||
|
{
|
||||||
|
match_len = XCA_GET16 (src);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
match_len += 0x0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match_len += 3;
|
||||||
|
if (match_offset_bits)
|
||||||
|
{
|
||||||
|
match_offset = ((accum >> (32 - match_offset_bits))
|
||||||
|
+ (1 << match_offset_bits));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
match_offset = 1;
|
||||||
|
}
|
||||||
|
accum <<= match_offset_bits;
|
||||||
|
extra_bits -= match_offset_bits;
|
||||||
|
if (extra_bits < 0)
|
||||||
|
{
|
||||||
|
accum |= (XCA_GET16 (src) << (-extra_bits));
|
||||||
|
extra_bits += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy data */
|
||||||
|
out_len += match_len;
|
||||||
|
if (buf)
|
||||||
|
{
|
||||||
|
copy = (out - match_offset);
|
||||||
|
while (match_len--)
|
||||||
|
*(out++) = *(copy++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allow for termination with no explicit end marker symbol */
|
||||||
|
if (src == end)
|
||||||
|
return out_len;
|
||||||
|
|
||||||
|
DBG ("XCA input overrun at output length %#zx\n", out_len);
|
||||||
|
return -1;
|
||||||
|
}
|
233
utils/bmtool.c
Normal file
233
utils/bmtool.c
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* ntloader -- Microsoft Windows NT6+ loader
|
||||||
|
* Copyright (C) 2025 A1ive.
|
||||||
|
*
|
||||||
|
* ntloader is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License,
|
||||||
|
* or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* ntloader is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ntloader. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "lznt1.h"
|
||||||
|
#include "xca.h"
|
||||||
|
|
||||||
|
#define BOOTMGR_MIN_LEN 16384
|
||||||
|
|
||||||
|
static void *
|
||||||
|
load_bootmgr (const char *path, size_t *len)
|
||||||
|
{
|
||||||
|
FILE *fp = fopen (path, "rb");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Error opening file '%s': %s\n",
|
||||||
|
path, strerror (errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek (fp, 0, SEEK_END) != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Error seeking file '%s': %s\n",
|
||||||
|
path, strerror(errno));
|
||||||
|
fclose (fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
long fsize = ftell (fp);
|
||||||
|
if (fsize <= 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Error getting file size '%s': %s\n",
|
||||||
|
path, strerror (errno));
|
||||||
|
fclose (fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rewind (fp);
|
||||||
|
|
||||||
|
char *buffer = malloc (fsize);
|
||||||
|
if (!buffer)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Memory allocation failed\n");
|
||||||
|
fclose (fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t read_size = fread (buffer, 1, fsize, fp);
|
||||||
|
if (read_size != (size_t) fsize)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Error reading file '%s'\n", path);
|
||||||
|
free (buffer);
|
||||||
|
fclose (fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose (fp);
|
||||||
|
*len = (size_t) fsize;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
write_data (const char *filename, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
FILE *fp = fopen(filename, "wb");
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "cannot open %s\n", filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytes_written = fwrite (data, 1, size, fp);
|
||||||
|
if (bytes_written != size)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "cannot write to %s\n", filename);
|
||||||
|
fclose (fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose (fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_empty_pgh (const void *pgh)
|
||||||
|
{
|
||||||
|
const uint32_t *dwords = pgh;
|
||||||
|
return ((dwords[0] | dwords[1] | dwords[2] | dwords[3]) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
decompress_bootmgr (const char *out, void *data, size_t len)
|
||||||
|
{
|
||||||
|
const uint8_t *cdata;
|
||||||
|
size_t offset;
|
||||||
|
size_t cdata_len;
|
||||||
|
ssize_t (* decompress) (const void *, size_t, void *);
|
||||||
|
ssize_t udata_len;
|
||||||
|
void *udata = NULL;
|
||||||
|
|
||||||
|
fprintf (stdout, "bootmgr @%p [%zu]\n", data, len);
|
||||||
|
|
||||||
|
/* Look for an embedded compressed bootmgr.exe on an
|
||||||
|
* eight-byte boundary.
|
||||||
|
*/
|
||||||
|
for (offset = BOOTMGR_MIN_LEN;
|
||||||
|
offset < (len - BOOTMGR_MIN_LEN);
|
||||||
|
offset += 0x08)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Initialise checks */
|
||||||
|
decompress = NULL;
|
||||||
|
cdata = (uint8_t *) data + offset;
|
||||||
|
cdata_len = len - offset;
|
||||||
|
|
||||||
|
/* Check for an embedded LZNT1-compressed bootmgr.exe.
|
||||||
|
* Since there is no way for LZNT1 to compress the
|
||||||
|
* initial "MZ" bytes of bootmgr.exe, we look for this
|
||||||
|
* signature starting three bytes after a paragraph
|
||||||
|
* boundary, with a preceding tag byte indicating that
|
||||||
|
* these two bytes would indeed be uncompressed.
|
||||||
|
*/
|
||||||
|
if (((offset & 0x0f) == 0x00) &&
|
||||||
|
((cdata[0x02] & 0x03) == 0x00) &&
|
||||||
|
(cdata[0x03] == 'M') &&
|
||||||
|
(cdata[0x04] == 'Z'))
|
||||||
|
{
|
||||||
|
fprintf (stdout,
|
||||||
|
"checking for LZNT1 bootmgr.exe at +0x%zx\n",
|
||||||
|
offset);
|
||||||
|
decompress = lznt1_decompress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for an embedded XCA-compressed bootmgr.exe.
|
||||||
|
* The bytes 0x00, 'M', and 'Z' will always be
|
||||||
|
* present, and so the corresponding symbols must have
|
||||||
|
* a non-zero Huffman length. The embedded image
|
||||||
|
* tends to have a large block of zeroes immediately
|
||||||
|
* beforehand, which we check for. It's implausible
|
||||||
|
* that the compressed data could contain substantial
|
||||||
|
* runs of zeroes, so we check for that too, in order
|
||||||
|
* to eliminate some common false positive matches.
|
||||||
|
*/
|
||||||
|
if (((cdata[0x00] & 0x0f) != 0x00) &&
|
||||||
|
((cdata[0x26] & 0xf0) != 0x00) &&
|
||||||
|
((cdata[0x2d] & 0x0f) != 0x00) &&
|
||||||
|
(is_empty_pgh (cdata - 0x10)) &&
|
||||||
|
(! is_empty_pgh ((cdata + 0x400))) &&
|
||||||
|
(! is_empty_pgh ((cdata + 0x800))) &&
|
||||||
|
(! is_empty_pgh ((cdata + 0xc00))))
|
||||||
|
{
|
||||||
|
fprintf (stdout,
|
||||||
|
"checking for XCA bootmgr.exe at +0x%zx\n",
|
||||||
|
offset);
|
||||||
|
decompress = xca_decompress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have not found a possible bootmgr.exe, skip
|
||||||
|
* to the next offset.
|
||||||
|
*/
|
||||||
|
if (! decompress)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Find length of decompressed image */
|
||||||
|
udata_len = decompress (cdata, cdata_len, NULL);
|
||||||
|
if (udata_len < 0)
|
||||||
|
{
|
||||||
|
/* May be a false positive signature match */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract decompressed image to memory */
|
||||||
|
fprintf (stdout, "extracting embedded bootmgr.exe\n");
|
||||||
|
udata = malloc (udata_len);
|
||||||
|
if (! udata)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "out of memory\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
decompress (cdata, cdata_len, udata);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (udata == NULL)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "no embedded bootmgr.exe found\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int rc = write_data (out, udata, udata_len);
|
||||||
|
free (udata);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Usage: %s BOOTMGR [BOOTMGR.EXE]\n",
|
||||||
|
argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len;
|
||||||
|
const char *out = argc >= 3 ? argv[2] : "bootmgr.exe";
|
||||||
|
void *data = load_bootmgr (argv[1], &len);
|
||||||
|
|
||||||
|
if (data == NULL)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
int rc = decompress_bootmgr (out, data, len);
|
||||||
|
|
||||||
|
free (data);
|
||||||
|
return rc;
|
||||||
|
}
|
@ -51,3 +51,16 @@ regview : $(REG_FILES)
|
|||||||
$(HOST_CC) $(HOST_CFLAGS) -iquote include/ $(REG_FILES) -o $@
|
$(HOST_CC) $(HOST_CFLAGS) -iquote include/ $(REG_FILES) -o $@
|
||||||
|
|
||||||
RM_FILES += regview regview.exe
|
RM_FILES += regview regview.exe
|
||||||
|
|
||||||
|
# bmtool
|
||||||
|
#
|
||||||
|
BMTOOL_FILES := libnt/huffman.c libnt/lznt1.c libnt/xca.c
|
||||||
|
BMTOOL_FILES += utils/bmtool.c
|
||||||
|
|
||||||
|
bmtool.exe : $(BMTOOL_FILES)
|
||||||
|
$(MINGW_CC) $(HOST_CFLAGS) -iquote include/ $(BMTOOL_FILES) -o $@
|
||||||
|
|
||||||
|
bmtool : $(BMTOOL_FILES)
|
||||||
|
$(HOST_CC) $(HOST_CFLAGS) -iquote include/ $(BMTOOL_FILES) -o $@
|
||||||
|
|
||||||
|
RM_FILES += bmtool bmtool.exe
|
||||||
|
Loading…
x
Reference in New Issue
Block a user