summaryrefslogtreecommitdiff
path: root/pkgtools
diff options
context:
space:
mode:
authoratatat <atatat>2004-07-23 03:37:26 +0000
committeratatat <atatat>2004-07-23 03:37:26 +0000
commit61e9c92033270017e5d9ced4eb917adbc4511595 (patch)
treeb9b8986031e6fa702e3a793ef789ad039df1821c /pkgtools
parent5d6d78529c554779f8b61175abe52a1733c711ad (diff)
downloadpkgsrc-61e9c92033270017e5d9ced4eb917adbc4511595.tar.gz
A small package to arbitrary tiny patches to binaries (where the
source cannot otherwise be patched).
Diffstat (limited to 'pkgtools')
-rw-r--r--pkgtools/binpatch/DESCR2
-rw-r--r--pkgtools/binpatch/Makefile31
-rw-r--r--pkgtools/binpatch/PLIST3
-rw-r--r--pkgtools/binpatch/files/binpatch.1116
-rw-r--r--pkgtools/binpatch/files/binpatch.c174
5 files changed, 326 insertions, 0 deletions
diff --git a/pkgtools/binpatch/DESCR b/pkgtools/binpatch/DESCR
new file mode 100644
index 00000000000..64ce39d7776
--- /dev/null
+++ b/pkgtools/binpatch/DESCR
@@ -0,0 +1,2 @@
+Apply small, arbitrary binary patches using an arcane command line
+syntax.
diff --git a/pkgtools/binpatch/Makefile b/pkgtools/binpatch/Makefile
new file mode 100644
index 00000000000..fd20af1eada
--- /dev/null
+++ b/pkgtools/binpatch/Makefile
@@ -0,0 +1,31 @@
+# $NetBSD: Makefile,v 1.1.1.1 2004/07/23 03:37:26 atatat Exp $
+#
+
+DISTNAME= binpatch-1.0
+CATEGORIES= pkgtools
+MASTER_SITES= # empty
+DISTFILES= # empty
+
+MAINTAINER= atatat@NetBSD.org
+HOMEPAGE= ftp://ftp.NetBSD.org/pub/NetBSD/packages/pkgsrc/Packages.txt
+COMMENT= Trivial binary patch applicator
+
+USE_BUILDLINK3= yes
+
+NO_CHECKSUM= # defined
+
+.include "../../mk/bsd.prefs.mk"
+
+do-extract:
+ @${CP} -Rp ${FILESDIR} ${WRKSRC}
+
+do-build:
+ @(cd ${WRKSRC}; \
+ ${ECHO} "${CC} -o binpatch binpatch.c"; \
+ ${CC} -o binpatch binpatch.c )
+
+do-install:
+ ${INSTALL_PROGRAM} ${WRKSRC}/binpatch ${PREFIX}/bin/binpatch
+ ${INSTALL_MAN} ${WRKSRC}/binpatch.1 ${PREFIX}/man/man1
+
+.include "../../mk/bsd.pkg.mk"
diff --git a/pkgtools/binpatch/PLIST b/pkgtools/binpatch/PLIST
new file mode 100644
index 00000000000..13f0c0b99f8
--- /dev/null
+++ b/pkgtools/binpatch/PLIST
@@ -0,0 +1,3 @@
+@comment $NetBSD: PLIST,v 1.1.1.1 2004/07/23 03:37:26 atatat Exp $
+bin/binpatch
+man/man1/binpatch.1
diff --git a/pkgtools/binpatch/files/binpatch.1 b/pkgtools/binpatch/files/binpatch.1
new file mode 100644
index 00000000000..8e7ef0930e5
--- /dev/null
+++ b/pkgtools/binpatch/files/binpatch.1
@@ -0,0 +1,116 @@
+.\" $NetBSD: binpatch.1,v 1.1.1.1 2004/07/23 03:37:26 atatat Exp $
+.\"
+.\" Copyright (c) 2004 by Andrew Brown <atatat@netbsd.org>
+.\" Absolutely no warranty.
+.\"
+.Dd July 20, 2004
+.Dt BINPATCH 1
+.Sh NAME
+.Nm binpatch
+.Nd trivial binary patch applicator
+.Sh SYNOPSIS
+.Nm
+.Pa file=...
+.Pa size=...
+.Pa offset=...
+.Pa compare=...
+.Pa skip=...
+.Pa replace=...
+.Sh DESCRIPTION
+The
+.Nm
+utility can read and replace a small section of a given file.
+It is designed for use in those instances where a problem exists with
+a given binary that cannot be reconstructed from source code, but the
+required change can be implemented by replacing a few bytes in the
+existing binary.
+All arguments must be given.
+.Sh EXAMPLES
+Given a binary called
+.Dq a.out
+of 10713 bytes in size with the following text segment:
+.Bd -literal -offset indent
+% objdump -h a.out
+.sp
+a.out: file format elf32-i386
+.sp
+Sections:
+Idx Name Size VMA LMA File off Algn
+[...]
+ 9 .text 00000be4 08048968 08048968 00000968 2**2
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+[...]
+% objdump -d -j .text a.out
+[...]
+ 8048b0f: 83 ef 04 sub $0x4,%edi
+ 8048b12: ff d0 call *%eax
+ 8048b14: 83 fe ff cmp $0xffffffff,%esi
+[...]
+.sp
+.Ed
+where we wish to elide the call through
+.Ar %eax
+by replacing it with a series of
+.Ar nop
+(or
+.Dq no operation )
+instructions (the machine code for this on the i386 platform is 0x90),
+we first calculate the offset into the file of the previous
+.Ar sub
+instruction. To do this, we take the address of the
+.Ar sub
+instruction as given by the dissassembly output, subtract the
+.Dq LMA
+and add the
+.Dq File off
+values from the objdump output (note that
+.Xr bc 1
+expects hexadecimal values to be given using upper case):
+.Bd -literal -offset indent
+% bc
+ibase=16
+8048B0F-08048968+00000968
+2831
+.sp
+.Ed
+The region of the binary we want to compare to before applying the
+patch is the concatenation of the relevant machine codes from the
+dissassembly dump (\c
+.Ar 83ef04ffd083feff )
+and the replacement is simply two
+.Ar nop
+instructions (\c
+.Ar 9090 ) ,
+that will replace the
+.Ar ffd0
+of the original call.
+The offset of the replacement is 3, since that is the number of bytes
+in the
+.Ar sub
+instruction.
+From this we have our patch:
+.Bd -literal -offset indent
+% binpatch file=a.out size=10713 offset=2831 \\
+ compare=83ef04ffd083feff skip=3 replace=9090
+% objdump -d -j .text a.out
+[...]
+ 8048b0f: 83 ef 04 sub $0x4,%edi
+ 8048b12: 90 nop
+ 8048b13: 90 nop
+ 8048b14: 83 fe ff cmp $0xffffffff,%esi
+[...]
+.sp
+.Ed
+And thus the call is removed.
+.Sh DIAGNOSTICS
+The diagnostics are terse and almost unhelpful, but are more verbose
+than users of
+.Xr ed 1
+might be used to.
+They typically mention the command line argument that was in error.
+.Sh SEE ALSO
+.Xr bc 1 ,
+.Xr objdump 1 ,
+.Xr patch 1
+.Sh AUTHORS
+.An Andrew Brown Aq atatat@netbsd.org
diff --git a/pkgtools/binpatch/files/binpatch.c b/pkgtools/binpatch/files/binpatch.c
new file mode 100644
index 00000000000..a80667f0bd4
--- /dev/null
+++ b/pkgtools/binpatch/files/binpatch.c
@@ -0,0 +1,174 @@
+/* $NetBSD: binpatch.c,v 1.1.1.1 2004/07/23 03:37:26 atatat Exp $ */
+
+/*
+ * ------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Andrew Brown <atatat@NetBSD.org> wrote this file. As long as you
+ * retain this notice you can do whatever you want with this stuff.
+ * If we meet some day, and you think this stuff is worth it, you can
+ * buy me a beer in return.
+ * ------------------------------------------------------------------------
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int
+die(int rc, const char *msg)
+{
+ if (rc)
+ perror(msg);
+ else
+ fprintf(stderr, "%s\n", msg);
+ exit(1);
+}
+
+static void
+cvt(const char *s, const char *i, unsigned char *o, size_t l)
+{
+ int t, x;
+
+ for (t = 0; t < l; t++) {
+ x = i[2 * t];
+ if (x >= '0' && x <= '9')
+ x -= '0';
+ else if (x >= 'a' && x <= 'f')
+ x -= 'a' - 10;
+ else if (x >= 'A' && x <= 'F')
+ x -= 'A' - 10;
+ else
+ die(0, s);
+ o[t] = x * 16;
+
+ x = i[2 * t + 1];
+ if (x >= '0' && x <= '9')
+ x -= '0';
+ else if (x >= 'a' && x <= 'f')
+ x -= 'a' - 10;
+ else if (x >= 'A' && x <= 'F')
+ x -= 'A' - 10;
+ else
+ die(0, s);
+ o[t] += x;
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct stat st;
+ char *key, *value;
+ int f, i;
+ unsigned char *buf, *get, *put;
+ size_t lget, lput;
+ off_t sz, cmp_off, skip_off;
+
+ f = -1;
+ get = put = NULL;
+ lget = lput = 0;
+ sz = cmp_off = skip_off = -1;
+
+ while (--argc > 0) {
+ key = *++argv;
+ if ((value = strchr(key, '=')) == NULL)
+ die(0, "value required");
+ else
+ *value++ = '\0';
+
+ if (strcmp(key, "file") == 0) {
+ f = open(value, O_RDWR);
+ if (f == -1)
+ die(1, "file");
+ }
+ else if (strcmp(key, "size") == 0) {
+ char *t;
+ errno = 0;
+ sz = strtol(value, &t, 0);
+ if (errno != 0)
+ die(1, "size");
+ }
+ else if (strcmp(key, "offset") == 0) {
+ char *t;
+ errno = 0;
+ cmp_off = strtol(value, &t, 0);
+ if (errno != 0)
+ die(1, "offset");
+ }
+ else if (strcmp(key, "compare") == 0) {
+ lget = strlen(value);
+ if (lget % 2 != 0)
+ die(0, "compare");
+ lget /= 2;
+ get = malloc(lget);
+ buf = malloc(lget);
+ cvt("compare", value, get, lget);
+ }
+ else if (strcmp(key, "skip") == 0) {
+ char *t;
+ errno = 0;
+ skip_off = strtol(value, &t, 0);
+ if (errno != 0)
+ die(1, "offset");
+ }
+ else if (strcmp(key, "replace") == 0) {
+ lput = strlen(value);
+ if (lput % 2 != 0)
+ die(0, "replace");
+ lput /= 2;
+ put = malloc(lput);
+ cvt("replace", value, put, lput);
+ }
+ }
+
+ /*
+ * ./binpatch
+ * file=${MOZILLA_HOME}/netscape
+ * size=13823336
+ * offset=0x008073e9
+ * compare=6a00e82406a3ffe81f0ca3ff
+ * skip=2
+ * replace=9090909090
+ */
+
+ if (f == -1)
+ die(0, "file missing");
+ if (get == NULL || lget == 0)
+ die(0, "compare missing");
+ if (put == NULL || lput == 0)
+ die(0, "replace missing");
+ if (sz == -1)
+ die(0, "size missing");
+ if (cmp_off == -1)
+ die(0, "offset missing");
+ if (skip_off == -1)
+ die(0, "skip missing");
+ if (skip_off < 0 ||
+ (skip_off == 0 && lput >= lget) ||
+ (skip_off > 0 && skip_off + lput > lget))
+ die(0, "illegal skip");
+
+ if (fstat(f, &st) == -1)
+ die(1, "fstat");
+ if (st.st_size != sz)
+ die(0, "wrong size");
+ if (lseek(f, cmp_off, SEEK_SET) == -1)
+ die(1, "lseek");
+ if (read(f, buf, lget) != lget)
+ die(1, "read");
+ if (memcmp(buf, get, lget) != 0)
+ die(0, "instructions not found");
+ if (lseek(f, cmp_off + skip_off, SEEK_SET) == -1)
+ die(1, "lseek");
+ if (write(f, put, lput) != lput)
+ die(1, "write");
+ if (close(f) != 0)
+ die(1, "close");
+
+ return (0);
+}