mirror of
				https://github.com/keylase/nvidia-patch.git
				synced 2025-11-03 22:22:01 +00:00 
			
		
		
		
	Merge pull request #47 from Snawoot/1337_diff_tool
Add tool for producing .1337 patches
This commit is contained in:
		
							
								
								
									
										119
									
								
								win/tools/1337-diff/1337-diff.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										119
									
								
								win/tools/1337-diff/1337-diff.py
									
									
									
									
									
										Executable 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()
 | 
			
		||||
							
								
								
									
										46
									
								
								win/tools/1337-diff/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								win/tools/1337-diff/README.md
									
									
									
									
									
										Normal 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.
 | 
			
		||||
		Reference in New Issue
	
	Block a user