From ca59ebf60df4ef45a1e4d681980e29e3db853bba Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 18 May 2017 06:43:51 +0100 Subject: Move MD5 out into its own file. This begins a programme of code reorganisation at the end of which I'd like to end up with something almost legible :-) --- Makefile.am | 2 +- fake-lib.c | 214 ----------------------------------------------- fake-lib.h | 4 +- fake-msi.c | 39 --------- md5.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 275 insertions(+), 255 deletions(-) create mode 100644 md5.c diff --git a/Makefile.am b/Makefile.am index 56da99e..6fb2062 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,7 +6,7 @@ lib_LTLIBRARIES = libwinterop.so.la libmsi.so.la libpreload.la libwinterop_so_la_SOURCES = fake-winterop.c fake-lib.c fake-lib.h -libmsi_so_la_SOURCES = fake-msi.c fake-lib.c fake-lib.h +libmsi_so_la_SOURCES = fake-msi.c fake-lib.c fake-lib.h md5.c libpreload_la_SOURCES = preload.c libpreload_la_LDFLAGS = -ldl diff --git a/fake-lib.c b/fake-lib.c index f2c949b..011d35d 100644 --- a/fake-lib.c +++ b/fake-lib.c @@ -140,217 +140,3 @@ unsigned le(const unsigned char *buf, size_t len, size_t off, size_t nbytes) } return toret; } - -/* ---------------------------------------------------------------------- - * Core MD5 algorithm: processes 16-word blocks into a message digest. - */ - -typedef struct { - uint32_t h[4]; -} MD5_Core_State; - -struct MD5Context { - MD5_Core_State core; - unsigned char block[64]; - int blkused; - uint32_t lenhi, lenlo; -}; - -#define F(x,y,z) ( ((x) & (y)) | ((~(x)) & (z)) ) -#define G(x,y,z) ( ((x) & (z)) | ((~(z)) & (y)) ) -#define H(x,y,z) ( (x) ^ (y) ^ (z) ) -#define I(x,y,z) ( (y) ^ ( (x) | ~(z) ) ) - -#define rol(x,y) ( ((x) << (y)) | (((uint32_t)x) >> (32-y)) ) - -#define subround(f,w,x,y,z,k,s,ti) \ - w = x + rol(w + f(x,y,z) + block[k] + ti, s) - -static void MD5_Core_Init(MD5_Core_State * s) -{ - s->h[0] = 0x67452301; - s->h[1] = 0xefcdab89; - s->h[2] = 0x98badcfe; - s->h[3] = 0x10325476; -} - -static void MD5_Block(MD5_Core_State * s, uint32_t * block) -{ - uint32_t a, b, c, d; - - a = s->h[0]; - b = s->h[1]; - c = s->h[2]; - d = s->h[3]; - - subround(F, a, b, c, d, 0, 7, 0xd76aa478); - subround(F, d, a, b, c, 1, 12, 0xe8c7b756); - subround(F, c, d, a, b, 2, 17, 0x242070db); - subround(F, b, c, d, a, 3, 22, 0xc1bdceee); - subround(F, a, b, c, d, 4, 7, 0xf57c0faf); - subround(F, d, a, b, c, 5, 12, 0x4787c62a); - subround(F, c, d, a, b, 6, 17, 0xa8304613); - subround(F, b, c, d, a, 7, 22, 0xfd469501); - subround(F, a, b, c, d, 8, 7, 0x698098d8); - subround(F, d, a, b, c, 9, 12, 0x8b44f7af); - subround(F, c, d, a, b, 10, 17, 0xffff5bb1); - subround(F, b, c, d, a, 11, 22, 0x895cd7be); - subround(F, a, b, c, d, 12, 7, 0x6b901122); - subround(F, d, a, b, c, 13, 12, 0xfd987193); - subround(F, c, d, a, b, 14, 17, 0xa679438e); - subround(F, b, c, d, a, 15, 22, 0x49b40821); - subround(G, a, b, c, d, 1, 5, 0xf61e2562); - subround(G, d, a, b, c, 6, 9, 0xc040b340); - subround(G, c, d, a, b, 11, 14, 0x265e5a51); - subround(G, b, c, d, a, 0, 20, 0xe9b6c7aa); - subround(G, a, b, c, d, 5, 5, 0xd62f105d); - subround(G, d, a, b, c, 10, 9, 0x02441453); - subround(G, c, d, a, b, 15, 14, 0xd8a1e681); - subround(G, b, c, d, a, 4, 20, 0xe7d3fbc8); - subround(G, a, b, c, d, 9, 5, 0x21e1cde6); - subround(G, d, a, b, c, 14, 9, 0xc33707d6); - subround(G, c, d, a, b, 3, 14, 0xf4d50d87); - subround(G, b, c, d, a, 8, 20, 0x455a14ed); - subround(G, a, b, c, d, 13, 5, 0xa9e3e905); - subround(G, d, a, b, c, 2, 9, 0xfcefa3f8); - subround(G, c, d, a, b, 7, 14, 0x676f02d9); - subround(G, b, c, d, a, 12, 20, 0x8d2a4c8a); - subround(H, a, b, c, d, 5, 4, 0xfffa3942); - subround(H, d, a, b, c, 8, 11, 0x8771f681); - subround(H, c, d, a, b, 11, 16, 0x6d9d6122); - subround(H, b, c, d, a, 14, 23, 0xfde5380c); - subround(H, a, b, c, d, 1, 4, 0xa4beea44); - subround(H, d, a, b, c, 4, 11, 0x4bdecfa9); - subround(H, c, d, a, b, 7, 16, 0xf6bb4b60); - subround(H, b, c, d, a, 10, 23, 0xbebfbc70); - subround(H, a, b, c, d, 13, 4, 0x289b7ec6); - subround(H, d, a, b, c, 0, 11, 0xeaa127fa); - subround(H, c, d, a, b, 3, 16, 0xd4ef3085); - subround(H, b, c, d, a, 6, 23, 0x04881d05); - subround(H, a, b, c, d, 9, 4, 0xd9d4d039); - subround(H, d, a, b, c, 12, 11, 0xe6db99e5); - subround(H, c, d, a, b, 15, 16, 0x1fa27cf8); - subround(H, b, c, d, a, 2, 23, 0xc4ac5665); - subround(I, a, b, c, d, 0, 6, 0xf4292244); - subround(I, d, a, b, c, 7, 10, 0x432aff97); - subround(I, c, d, a, b, 14, 15, 0xab9423a7); - subround(I, b, c, d, a, 5, 21, 0xfc93a039); - subround(I, a, b, c, d, 12, 6, 0x655b59c3); - subround(I, d, a, b, c, 3, 10, 0x8f0ccc92); - subround(I, c, d, a, b, 10, 15, 0xffeff47d); - subround(I, b, c, d, a, 1, 21, 0x85845dd1); - subround(I, a, b, c, d, 8, 6, 0x6fa87e4f); - subround(I, d, a, b, c, 15, 10, 0xfe2ce6e0); - subround(I, c, d, a, b, 6, 15, 0xa3014314); - subround(I, b, c, d, a, 13, 21, 0x4e0811a1); - subround(I, a, b, c, d, 4, 6, 0xf7537e82); - subround(I, d, a, b, c, 11, 10, 0xbd3af235); - subround(I, c, d, a, b, 2, 15, 0x2ad7d2bb); - subround(I, b, c, d, a, 9, 21, 0xeb86d391); - - s->h[0] += a; - s->h[1] += b; - s->h[2] += c; - s->h[3] += d; -} - -/* ---------------------------------------------------------------------- - * Outer MD5 algorithm: take an arbitrary length byte string, - * convert it into 16-word blocks with the prescribed padding at - * the end, and pass those blocks to the core MD5 algorithm. - */ - -#define BLKSIZE 64 - -void MD5Init(struct MD5Context *s) -{ - MD5_Core_Init(&s->core); - s->blkused = 0; - s->lenhi = s->lenlo = 0; -} - -void MD5Update(struct MD5Context *s, unsigned char const *p, unsigned len) -{ - unsigned char *q = (unsigned char *) p; - uint32_t wordblock[16]; - uint32_t lenw = len; - int i; - - /* - * Update the length field. - */ - s->lenlo += lenw; - s->lenhi += (s->lenlo < lenw); - - if (s->blkused + len < BLKSIZE) { - /* - * Trivial case: just add to the block. - */ - memcpy(s->block + s->blkused, q, len); - s->blkused += len; - } else { - /* - * We must complete and process at least one block. - */ - while (s->blkused + len >= BLKSIZE) { - memcpy(s->block + s->blkused, q, BLKSIZE - s->blkused); - q += BLKSIZE - s->blkused; - len -= BLKSIZE - s->blkused; - /* Now process the block. Gather bytes little-endian into words */ - for (i = 0; i < 16; i++) { - wordblock[i] = - (((uint32_t) s->block[i * 4 + 3]) << 24) | - (((uint32_t) s->block[i * 4 + 2]) << 16) | - (((uint32_t) s->block[i * 4 + 1]) << 8) | - (((uint32_t) s->block[i * 4 + 0]) << 0); - } - MD5_Block(&s->core, wordblock); - s->blkused = 0; - } - memcpy(s->block, q, len); - s->blkused = len; - } -} - -void MD5Final(uint32_t output[4], struct MD5Context *s) -{ - int i; - unsigned pad; - unsigned char c[64]; - uint32_t lenhi, lenlo; - - if (s->blkused >= 56) - pad = 56 + 64 - s->blkused; - else - pad = 56 - s->blkused; - - lenhi = (s->lenhi << 3) | (s->lenlo >> (32 - 3)); - lenlo = (s->lenlo << 3); - - memset(c, 0, pad); - c[0] = 0x80; - MD5Update(s, c, pad); - - c[7] = (lenhi >> 24) & 0xFF; - c[6] = (lenhi >> 16) & 0xFF; - c[5] = (lenhi >> 8) & 0xFF; - c[4] = (lenhi >> 0) & 0xFF; - c[3] = (lenlo >> 24) & 0xFF; - c[2] = (lenlo >> 16) & 0xFF; - c[1] = (lenlo >> 8) & 0xFF; - c[0] = (lenlo >> 0) & 0xFF; - - MD5Update(s, c, 8); - - for (i = 0; i < 4; i++) - output[i] = s->core.h[i]; -} - -void MD5Simple(void const *p, unsigned len, uint32_t output[4]) -{ - struct MD5Context s; - - MD5Init(&s); - MD5Update(&s, (unsigned char const *)p, len); - MD5Final(output, &s); -} diff --git a/fake-lib.h b/fake-lib.h index 99a6eec..0b7f8f9 100644 --- a/fake-lib.h +++ b/fake-lib.h @@ -1,3 +1,6 @@ +#include +#include + char *ascii(const char16_t *wstr, bool translate_slashes); void system_argv(const char *cmd, ...); void system_argv_array(char **args); @@ -6,7 +9,6 @@ void *smalloc(size_t size); void *srealloc(void *ptr, size_t size); char *dupcat(const char *str, ...); unsigned le(const unsigned char *buf, size_t len, size_t off, size_t nbytes); -void MD5Simple(void const *p, unsigned len, uint32_t output[4]); #define snew(type) ((type *)smalloc(sizeof(type))) #define snewn(n,type) ((type *)smalloc((n)*sizeof(type))) diff --git a/fake-msi.c b/fake-msi.c index 25a43a1..bf49911 100644 --- a/fake-msi.c +++ b/fake-msi.c @@ -199,45 +199,6 @@ uint32_t MsiGetFileVersionW(const char16_t *filename, return toret; } -struct MsiHash { - uint32_t structure_size; - uint32_t hash_words[4]; -}; - -uint32_t MsiGetFileHashW(const char16_t *filename, uint32_t options, - struct MsiHash *hash) -{ - char *fname = ascii(filename, true); - int fd = -1; - void *mapv = MAP_FAILED; - uint32_t toret; - - fd = open(fname, O_RDONLY); - if (fd < 0) - err(1, "%s: open", fname); - struct stat st; - if (fstat(fd, &st) < 0) - err(1, "%s: fstat", fname); - size_t fsize = st.st_size; - mapv = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0); - if (mapv == MAP_FAILED) - err(1, "%s: mmap", fname); - - MD5Simple(mapv, fsize, hash->hash_words); - warnx("MsiGetFileHash(%s) -> %08x:%08x:%08x:%08x", fname, - (unsigned)hash->hash_words[0], (unsigned)hash->hash_words[1], - (unsigned)hash->hash_words[2], (unsigned)hash->hash_words[3]); - toret = 0; - - cleanup: - if (mapv != MAP_FAILED) - munmap(mapv, fsize); - if (fd != -1) - close(fd); - sfree(fname); - return toret; -} - typedef struct MsiTypePrefix { enum { MAIN, VIEW, RECORD } type; } MsiTypePrefix; diff --git a/md5.c b/md5.c new file mode 100644 index 0000000..48c6aec --- /dev/null +++ b/md5.c @@ -0,0 +1,271 @@ +/* + * Implement MsiGetFileHash(). + * + * Experimenting with a small test program on Windows calling the + * original version of that function suggests that the hash it + * implements is just MD5, only repackaged as an array of four + * little-endian 32-bit words instead of the usual 16 bytes. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "fake-lib.h" + +/* ---------------------------------------------------------------------- + * Core MD5 algorithm: processes 16-word blocks into a message digest. + */ + +typedef struct { + uint32_t h[4]; +} MD5_Core_State; + +struct MD5Context { + MD5_Core_State core; + unsigned char block[64]; + int blkused; + uint64_t len; +}; + +#define F(x,y,z) ( ((x) & (y)) | ((~(x)) & (z)) ) +#define G(x,y,z) ( ((x) & (z)) | ((~(z)) & (y)) ) +#define H(x,y,z) ( (x) ^ (y) ^ (z) ) +#define I(x,y,z) ( (y) ^ ( (x) | ~(z) ) ) + +#define rol(x,y) ( ((x) << (y)) | (((uint32_t)x) >> (32-y)) ) + +#define subround(f,w,x,y,z,k,s,ti) \ + w = x + rol(w + f(x,y,z) + block[k] + ti, s) + +static void MD5_Core_Init(MD5_Core_State * s) +{ + s->h[0] = 0x67452301; + s->h[1] = 0xefcdab89; + s->h[2] = 0x98badcfe; + s->h[3] = 0x10325476; +} + +static void MD5_Block(MD5_Core_State * s, uint32_t * block) +{ + uint32_t a, b, c, d; + + a = s->h[0]; + b = s->h[1]; + c = s->h[2]; + d = s->h[3]; + + subround(F, a, b, c, d, 0, 7, 0xd76aa478); + subround(F, d, a, b, c, 1, 12, 0xe8c7b756); + subround(F, c, d, a, b, 2, 17, 0x242070db); + subround(F, b, c, d, a, 3, 22, 0xc1bdceee); + subround(F, a, b, c, d, 4, 7, 0xf57c0faf); + subround(F, d, a, b, c, 5, 12, 0x4787c62a); + subround(F, c, d, a, b, 6, 17, 0xa8304613); + subround(F, b, c, d, a, 7, 22, 0xfd469501); + subround(F, a, b, c, d, 8, 7, 0x698098d8); + subround(F, d, a, b, c, 9, 12, 0x8b44f7af); + subround(F, c, d, a, b, 10, 17, 0xffff5bb1); + subround(F, b, c, d, a, 11, 22, 0x895cd7be); + subround(F, a, b, c, d, 12, 7, 0x6b901122); + subround(F, d, a, b, c, 13, 12, 0xfd987193); + subround(F, c, d, a, b, 14, 17, 0xa679438e); + subround(F, b, c, d, a, 15, 22, 0x49b40821); + subround(G, a, b, c, d, 1, 5, 0xf61e2562); + subround(G, d, a, b, c, 6, 9, 0xc040b340); + subround(G, c, d, a, b, 11, 14, 0x265e5a51); + subround(G, b, c, d, a, 0, 20, 0xe9b6c7aa); + subround(G, a, b, c, d, 5, 5, 0xd62f105d); + subround(G, d, a, b, c, 10, 9, 0x02441453); + subround(G, c, d, a, b, 15, 14, 0xd8a1e681); + subround(G, b, c, d, a, 4, 20, 0xe7d3fbc8); + subround(G, a, b, c, d, 9, 5, 0x21e1cde6); + subround(G, d, a, b, c, 14, 9, 0xc33707d6); + subround(G, c, d, a, b, 3, 14, 0xf4d50d87); + subround(G, b, c, d, a, 8, 20, 0x455a14ed); + subround(G, a, b, c, d, 13, 5, 0xa9e3e905); + subround(G, d, a, b, c, 2, 9, 0xfcefa3f8); + subround(G, c, d, a, b, 7, 14, 0x676f02d9); + subround(G, b, c, d, a, 12, 20, 0x8d2a4c8a); + subround(H, a, b, c, d, 5, 4, 0xfffa3942); + subround(H, d, a, b, c, 8, 11, 0x8771f681); + subround(H, c, d, a, b, 11, 16, 0x6d9d6122); + subround(H, b, c, d, a, 14, 23, 0xfde5380c); + subround(H, a, b, c, d, 1, 4, 0xa4beea44); + subround(H, d, a, b, c, 4, 11, 0x4bdecfa9); + subround(H, c, d, a, b, 7, 16, 0xf6bb4b60); + subround(H, b, c, d, a, 10, 23, 0xbebfbc70); + subround(H, a, b, c, d, 13, 4, 0x289b7ec6); + subround(H, d, a, b, c, 0, 11, 0xeaa127fa); + subround(H, c, d, a, b, 3, 16, 0xd4ef3085); + subround(H, b, c, d, a, 6, 23, 0x04881d05); + subround(H, a, b, c, d, 9, 4, 0xd9d4d039); + subround(H, d, a, b, c, 12, 11, 0xe6db99e5); + subround(H, c, d, a, b, 15, 16, 0x1fa27cf8); + subround(H, b, c, d, a, 2, 23, 0xc4ac5665); + subround(I, a, b, c, d, 0, 6, 0xf4292244); + subround(I, d, a, b, c, 7, 10, 0x432aff97); + subround(I, c, d, a, b, 14, 15, 0xab9423a7); + subround(I, b, c, d, a, 5, 21, 0xfc93a039); + subround(I, a, b, c, d, 12, 6, 0x655b59c3); + subround(I, d, a, b, c, 3, 10, 0x8f0ccc92); + subround(I, c, d, a, b, 10, 15, 0xffeff47d); + subround(I, b, c, d, a, 1, 21, 0x85845dd1); + subround(I, a, b, c, d, 8, 6, 0x6fa87e4f); + subround(I, d, a, b, c, 15, 10, 0xfe2ce6e0); + subround(I, c, d, a, b, 6, 15, 0xa3014314); + subround(I, b, c, d, a, 13, 21, 0x4e0811a1); + subround(I, a, b, c, d, 4, 6, 0xf7537e82); + subround(I, d, a, b, c, 11, 10, 0xbd3af235); + subround(I, c, d, a, b, 2, 15, 0x2ad7d2bb); + subround(I, b, c, d, a, 9, 21, 0xeb86d391); + + s->h[0] += a; + s->h[1] += b; + s->h[2] += c; + s->h[3] += d; +} + +/* ---------------------------------------------------------------------- + * Outer MD5 algorithm: take an arbitrary length byte string, + * convert it into 16-word blocks with the prescribed padding at + * the end, and pass those blocks to the core MD5 algorithm. + */ + +#define BLKSIZE 64 + +static void MD5Init(struct MD5Context *s) +{ + MD5_Core_Init(&s->core); + s->blkused = 0; + s->len = 0; +} + +static void MD5Update(struct MD5Context *s, unsigned char const *p, + unsigned len) +{ + unsigned char *q = (unsigned char *) p; + uint32_t wordblock[16]; + int i; + + /* + * Update the length field. + */ + s->len += len; + + if (s->blkused + len < BLKSIZE) { + /* + * Trivial case: just add to the block. + */ + memcpy(s->block + s->blkused, q, len); + s->blkused += len; + } else { + /* + * We must complete and process at least one block. + */ + while (s->blkused + len >= BLKSIZE) { + memcpy(s->block + s->blkused, q, BLKSIZE - s->blkused); + q += BLKSIZE - s->blkused; + len -= BLKSIZE - s->blkused; + /* Now process the block. Gather bytes little-endian into words */ + for (i = 0; i < 16; i++) { + wordblock[i] = + (((uint32_t) s->block[i * 4 + 3]) << 24) | + (((uint32_t) s->block[i * 4 + 2]) << 16) | + (((uint32_t) s->block[i * 4 + 1]) << 8) | + (((uint32_t) s->block[i * 4 + 0]) << 0); + } + MD5_Block(&s->core, wordblock); + s->blkused = 0; + } + memcpy(s->block, q, len); + s->blkused = len; + } +} + +static void MD5Final(uint32_t output[4], struct MD5Context *s) +{ + int i; + unsigned pad; + unsigned char c[64]; + uint64_t len; + + if (s->blkused >= 56) + pad = 56 + 64 - s->blkused; + else + pad = 56 - s->blkused; + + len = s->len << 3; + + memset(c, 0, pad); + c[0] = 0x80; + MD5Update(s, c, pad); + + c[7] = (len >> (8*7)) & 0xFF; + c[6] = (len >> (8*6)) & 0xFF; + c[5] = (len >> (8*5)) & 0xFF; + c[4] = (len >> (8*4)) & 0xFF; + c[3] = (len >> (8*3)) & 0xFF; + c[2] = (len >> (8*2)) & 0xFF; + c[1] = (len >> (8*1)) & 0xFF; + c[0] = (len >> (8*0)) & 0xFF; + + MD5Update(s, c, 8); + + for (i = 0; i < 4; i++) + output[i] = s->core.h[i]; +} + +struct MsiHash { + uint32_t structure_size; + uint32_t hash_words[4]; +}; + +uint32_t MsiGetFileHashW(const char16_t *filename, uint32_t options, + struct MsiHash *hash) +{ + char *fname = ascii(filename, true); + uint32_t toret; + char buffer[4096]; + int fd = -1, retd; + struct MD5Context ctx; + + fd = open(fname, O_RDONLY); + if (fd < 0) { + /* Could do some better errno -> GetLastError translation here */ + warnx("MsiGetFileHash(%s) -> ERROR_OPEN_FAILED", fname); + toret = 110; + goto cleanup; + } + + MD5Init(&ctx); + + while ((retd = read(fd, buffer, sizeof(buffer)) > 0)) + MD5Update(&ctx, buffer, retd); + if (retd < 0) { + warnx("MsiGetFileHash(%s) -> ERROR_READ_FAULT", fname); + toret = 30; + goto cleanup; + } + + MD5Final(hash->hash_words, &ctx); + + warnx("MsiGetFileHash(%s) -> %08x:%08x:%08x:%08x", fname, + (unsigned)hash->hash_words[0], (unsigned)hash->hash_words[1], + (unsigned)hash->hash_words[2], (unsigned)hash->hash_words[3]); + toret = 0; + + cleanup: + if (fd != -1) + close(fd); + sfree(fname); + return toret; +} -- cgit v1.2.3-55-g6feb