Add tool for producing .1337 patches

This commit is contained in:
Vladislav Yarmak 2019-02-05 21:05:17 +02:00
parent 241a8aa81a
commit 0123fbd6ae
2 changed files with 165 additions and 0 deletions

119
win/tools/1337-diff/1337-diff.py Executable file
View File

@ -0,0 +1,119 @@
#!/usr/bin/env python3
import sys
import argparse
import os.path
import itertools
PATCH_EXT = ".1337"
CRLF = b"\x0d\x0a"
HEADER_FORMAT = b">%s"
LINE_FORMAT = CRLF + b"%016X:%02X->%02X"
OFFSET_ADJUSTMENT = 0xC00
class ByteDiffException(Exception):
""" Base class for all exceptions """
pass
class LengthMismatchException(ByteDiffException):
""" Throwed when length of input sequences do not match """
pass
def check_positive_int(value):
value = int(value)
if value <= 0:
raise argparse.ArgumentTypeError(
"%s is an invalid positive number value" % value)
return value
def parse_args():
parser = argparse.ArgumentParser(
description="Make .1337 patch file from original and patched files")
parser.add_argument("orig_file",
metavar="ORIG_FILE",
help="original file")
parser.add_argument("patched_file",
metavar="PATCHED_FILE",
help="patched file")
parser.add_argument("output_file",
metavar="OUTPUT_FILE",
nargs='?',
help="filename for patch output. Default: basename of "
"original filename with .1337 extension")
parser.add_argument("-f", "--header-filename",
metavar="FILENAME",
help="filename specified in resulting patch header. "
"Default: basename of original filename.")
parser.add_argument("-l", "--limit",
help="stop after number of differences",
type=check_positive_int)
args = parser.parse_args()
return args
def feed_chunks(f, chunk_size=4096):
""" Reads file-like object with chunks having up to `chunk_size` length """
while True:
buf = f.read(chunk_size)
if not buf:
break
yield buf
def zip_files_bytes(*files):
""" Iterate over two files, returning pair of bytes.
Throw LengthMismatch if file sizes is uneven. """
class EndMarker(object):
pass
end_marker = EndMarker()
iterators = (itertools.chain.from_iterable(feed_chunks(f)) for f in files)
for tup in itertools.zip_longest(*iterators, fillvalue=end_marker):
if any(v is end_marker for v in tup):
raise LengthMismatchException("Length of input files inequal.")
yield tup
def diff(left, right):
for offset, (a, b) in enumerate(zip_files_bytes(left, right)):
if a != b:
yield offset, a, b
def compose_diff_file(orig, patched, output, header, offset_adjustment=True):
output.write(HEADER_FORMAT % (header.encode('latin-1'),))
for offset, a, b in diff(orig, patched):
o = offset + OFFSET_ADJUSTMENT if offset_adjustment else offset
output.write(LINE_FORMAT % (o, a, b))
def main():
args = parse_args()
output_filename = args.output_file
if not output_filename:
orig_bname = os.path.basename(args.orig_file)
before, _, after = orig_bname.rpartition('.')
orig_bname_noext = before if before else after
output_filename = orig_bname_noext + PATCH_EXT
header_filename = args.header_filename
if not header_filename:
header_filename = os.path.basename(args.orig_file)
with open(args.orig_file, 'rb') as orig,\
open(args.patched_file, 'rb') as patched,\
open(output_filename, 'wb') as output:
try:
compose_diff_file(orig, patched, output, header_filename)
except LengthMismatchException:
print("Input files have inequal length. Aborting...",
file=sys.stderr)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,46 @@
1337-diff
=========
This tool accepts two input files and produces patch (diff) in `.1337`-file format. This format is compatible with patches produced by [x64dbg](https://x64dbg.com/) and applied by [Win\_1337\_Apply\_Patch tool](https://github.com/Deltafox79/Win_1337_Apply_Patch).
This tool is intended for internal usage to automate routine tasks related to windows patches. Implementation is really slow and prefers code transparency and correctness over speed.
## Requirements
* Python 3
## Synopsys
```
$ ./1337-diff.py -h
usage: 1337-diff.py [-h] [-f FILENAME] [-l LIMIT]
ORIG_FILE PATCHED_FILE [OUTPUT_FILE]
Make .1337 patch file from original and patched files
positional arguments:
ORIG_FILE original file
PATCHED_FILE patched file
OUTPUT_FILE filename for patch output. Default: basename of
original filename with .1337 extension
optional arguments:
-h, --help show this help message and exit
-f FILENAME, --header-filename FILENAME
filename specified in resulting patch header. Default:
basename of original filename.
-l LIMIT, --limit LIMIT
stop after number of differences
```
## Example
```
$ ./1337-diff.py ~/w418.81/orig/nvcuvid.dll ~/w418.81/patched/nvcuvid.dll
$ cat nvcuvid.1337
>nvcuvid.dll
00000000000DE736:74->90
00000000000DE737:08->90$
```
Note no newline at the end of file and CRLF line breaks.