Advertisement
Guest User

SMB Patcher

a guest
Oct 22nd, 2015
235
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 24.14 KB | None | 0 0
  1. #!/usr/bin/env python
  2. """Super Meat Boy Patcher version 1.1. Performs binary patches on
  3. the Super Meat Boy executable for various purposes.
  4. Works with Python 2.x, NOT 3.x currently.
  5. For Windows (32/64bit) and Linux (64bit):
  6.    Removes randomness from Larry ensuring 3 cycles.
  7. For Windows (32/64bit):
  8.    Removes Glitch Girl randomness, allows Glitch Girl
  9.    to spawn more often.
  10.  
  11. Usage: run with python, GUI should show automatically.
  12.  
  13. GPL v2, or above if you wish.
  14. d265f27.
  15. """
  16.  
  17. # Larry Script - What it does:
  18. # SMB has a GetRandomInt() function. Larry has two functions,
  19. # RaptureBoss::UpdateMaggot(RaptureBoss::Maggot*) and
  20. # RaptureBoss::RenderMaggot(RaptureBoss::Maggot*), that call it.
  21. # UpdateMaggot has 5 calls to GetRandomInt, RenderMaggot has 1.
  22. # We replace these function calls with specified return values,
  23. # removing RNG from Larry.
  24. # GetRandomInt() is trivial to find in the Linux executable due to it
  25. # being unstripped, below is the location of GetRandomInt() for Windows:
  26. # 0x4047d0 or SuperMeatBoy.eye+47d0 (Cheat Engine)
  27. # The values were randomly guessed by myself just to achieve the 3
  28. # cycle, so may not be perfectly accurate.
  29.  
  30. # Glitch Girl - What it does:
  31. # Glitch Girl has a GetRandomInt() call, we replace it with a particular
  32. # result to ensure she always spawns if possible.
  33. # To increase when she can possibly spawn we remove some jmp instructions
  34. # for if she shouldn't spawn.
  35.  
  36. import struct
  37.  
  38. import Tkinter as tk
  39. import tkFileDialog
  40. import tkMessageBox
  41.  
  42. LINUX_64_LARRY_STRING = "Linux executable with larry script."
  43. LINUX_64_NO_LARRY_STRING = "Linux executable without larry script."
  44. WINDOWS_LARRY_STRING = "Windows executable with larry script."
  45. WINDOWS_NO_LARRY_STRING = "Windows executable without larry script."
  46. UNKNOWN_LARRY_STRING = "Unknown executable. Couldn't find larry script positions."
  47.  
  48. WINDOWS_GLITCH_STRING = "Has patched Glitch Girl RNG."
  49. WINDOWS_NO_GLITCH_STRING = "Has normal Glitch Girl RNG."
  50. UNKNOWN_GLITCH_STRING = "Unknown Glitch Girl RNG data."
  51.  
  52. WINDOWS_MULTIPLE_GLITCH_STRING = "Ignores GG spawn requirements."
  53. WINDOWS_NO_MULTIPLE_GLITCH_STRING = "Does not ignore GG spawn requirements."
  54. UNKNOWN_MULTIPLE_GLITCH_STRING = "Unknown multiple Glitch Girls data."
  55.  
  56. NO_EXECUTABLE_FILE_STRING = "BACKUP EXECUTABLE BEFORE USE!\nNo executable currently selected."
  57.  
  58.  
  59.  
  60. def create_mov_instruction(value):
  61.     """Generates a mov instruction to work as a return value.
  62.    mov $0x(hex of value),%eax
  63.    Example:
  64.    create_mov_instruction(1):
  65.     b8 01 00 00 00          mov    $0x1,%eax"""
  66.     return "\xb8" + struct.pack("I", value)
  67.  
  68.  
  69.  
  70. # Binary information.
  71. # The following are the instructions we need to patch, with extra bytes so we select the correct ones.
  72. # Calls 1 - 5 are from UpdateMaggot, in order. Call 6 is from RenderMaggot.
  73.  
  74. ############################################################################################
  75. # WINDOWS file information.
  76.  
  77. # _EXTRA is extra instructions past the instruction we want so we can search effectively.
  78. WINDOWS_LARRY_1_EXTRA = "\x83\xc4\x08\x56\x8b\xcf\xe8\xd7\xfb\xff\xff"
  79. WINDOWS_LARRY_2_EXTRA = "\x89\x44\x24\x38\xdb\x44\x24\x38\xeb\x17"
  80. WINDOWS_LARRY_3_EXTRA = "\x89\x44\x24\x38\xdb\x44\x24\x38"
  81. WINDOWS_LARRY_4_EXTRA = "\x8b\x0d\xbc\x54\x6d\x00\x89\x44\x24\x38"
  82. WINDOWS_LARRY_5_EXTRA = "\x83\xc4\x08\x83\xf8\x32\x7e\x39\x33\xc9"
  83. WINDOWS_LARRY_6_EXTRA = "\x83\xc4\x08\x83\xf8\x32\x7d\x14\x89\x9e\xd8\x00\x00\x00"
  84.  
  85. # The instruction we are patching out.
  86. WINDOWS_LARRY_1_UNPATCHED_START = "\xe8\xd2\x7f\xf7\xff"
  87. WINDOWS_LARRY_2_UNPATCHED_START = "\xe8\xa6\x7f\xf7\xff"
  88. WINDOWS_LARRY_3_UNPATCHED_START = "\xe8\x8d\x7f\xf7\xff"
  89. WINDOWS_LARRY_4_UNPATCHED_START = "\xe8\x63\x7f\xf7\xff"
  90. WINDOWS_LARRY_5_UNPATCHED_START = "\xe8\x81\x7e\xf7\xff"
  91. WINDOWS_LARRY_6_UNPATCHED_START = "\xe8\xcf\x86\xf7\xff"
  92.  
  93. WINDOWS_UNPATCHED_LARRY_1 = WINDOWS_LARRY_1_UNPATCHED_START + WINDOWS_LARRY_1_EXTRA
  94. WINDOWS_UNPATCHED_LARRY_2 = WINDOWS_LARRY_2_UNPATCHED_START + WINDOWS_LARRY_2_EXTRA
  95. WINDOWS_UNPATCHED_LARRY_3 = WINDOWS_LARRY_3_UNPATCHED_START + WINDOWS_LARRY_3_EXTRA
  96. WINDOWS_UNPATCHED_LARRY_4 = WINDOWS_LARRY_4_UNPATCHED_START + WINDOWS_LARRY_4_EXTRA
  97. WINDOWS_UNPATCHED_LARRY_5 = WINDOWS_LARRY_5_UNPATCHED_START + WINDOWS_LARRY_5_EXTRA
  98. WINDOWS_UNPATCHED_LARRY_6 = WINDOWS_LARRY_6_UNPATCHED_START + WINDOWS_LARRY_6_EXTRA
  99.  
  100. # Here the magic happens, the replacement call values. Select whatever generates 3 cycles.
  101. WINDOWS_LARRY_RETURN_1 = 1000
  102. WINDOWS_LARRY_RETURN_2 = 1000
  103. WINDOWS_LARRY_RETURN_3 = 10
  104. WINDOWS_LARRY_RETURN_4 = 100
  105. WINDOWS_LARRY_RETURN_5 = 1000
  106. WINDOWS_LARRY_RETURN_6 = 10
  107.  
  108. WINDOWS_LARRY_1_PATCHED_START = create_mov_instruction(WINDOWS_LARRY_RETURN_1)
  109. WINDOWS_LARRY_2_PATCHED_START = create_mov_instruction(WINDOWS_LARRY_RETURN_2)
  110. WINDOWS_LARRY_3_PATCHED_START = create_mov_instruction(WINDOWS_LARRY_RETURN_3)
  111. WINDOWS_LARRY_4_PATCHED_START = create_mov_instruction(WINDOWS_LARRY_RETURN_4)
  112. WINDOWS_LARRY_5_PATCHED_START = create_mov_instruction(WINDOWS_LARRY_RETURN_5)
  113. WINDOWS_LARRY_6_PATCHED_START = create_mov_instruction(WINDOWS_LARRY_RETURN_6)
  114.  
  115. WINDOWS_PATCHED_LARRY_1 = WINDOWS_LARRY_1_PATCHED_START + WINDOWS_LARRY_1_EXTRA
  116. WINDOWS_PATCHED_LARRY_2 = WINDOWS_LARRY_2_PATCHED_START + WINDOWS_LARRY_2_EXTRA
  117. WINDOWS_PATCHED_LARRY_3 = WINDOWS_LARRY_3_PATCHED_START + WINDOWS_LARRY_3_EXTRA
  118. WINDOWS_PATCHED_LARRY_4 = WINDOWS_LARRY_4_PATCHED_START + WINDOWS_LARRY_4_EXTRA
  119. WINDOWS_PATCHED_LARRY_5 = WINDOWS_LARRY_5_PATCHED_START + WINDOWS_LARRY_5_EXTRA
  120. WINDOWS_PATCHED_LARRY_6 = WINDOWS_LARRY_6_PATCHED_START + WINDOWS_LARRY_6_EXTRA
  121.  
  122.  
  123. WINDOWS_PATCHED_LARRY_STRINGS = [WINDOWS_PATCHED_LARRY_1, WINDOWS_PATCHED_LARRY_2,
  124.             WINDOWS_PATCHED_LARRY_3, WINDOWS_PATCHED_LARRY_4,
  125.             WINDOWS_PATCHED_LARRY_5, WINDOWS_PATCHED_LARRY_6]
  126. WINDOWS_UNPATCHED_LARRY_STRINGS = [WINDOWS_UNPATCHED_LARRY_1, WINDOWS_UNPATCHED_LARRY_2,
  127.             WINDOWS_UNPATCHED_LARRY_3, WINDOWS_UNPATCHED_LARRY_4,
  128.             WINDOWS_UNPATCHED_LARRY_5, WINDOWS_UNPATCHED_LARRY_6]
  129.  
  130. # Glitch RNG.
  131. WINDOWS_GLITCH_EXTRA = "\x83\xc4\x08\x33\xd2\x3b\xc6\x0f\x9c\xc2\x5e\x5f\x8b\xc2"
  132. WINDOWS_GLITCH_UNPATCHED_START = "\xe8\x2e\x4b\xfe\xff"
  133. WINDOWS_GLITCH_UNPATCHED = WINDOWS_GLITCH_UNPATCHED_START + WINDOWS_GLITCH_EXTRA
  134. WINDOWS_GLITCH_PATCHED_VALUE = 0 # The number we replace the call instruction with.
  135. WINDOWS_GLITCH_PATCHED_START = create_mov_instruction(WINDOWS_GLITCH_PATCHED_VALUE)
  136. WINDOWS_GLITCH_PATCHED = WINDOWS_GLITCH_PATCHED_START + WINDOWS_GLITCH_EXTRA
  137.  
  138. # Multiple Glitch.
  139. # Okay, the following is tricky. The checks that occur to make sure you
  140. # only get glitch girl at the appropriate times start at around
  141. # 41fc52:   75 5d                   jne    0x41fcb1
  142. # So if we replace this conditional jump with an unconditional jump to
  143. # the start of the place where glitch girl rng occurs, namely 41fc96
  144. # Then glitch girl occurs more frequently.
  145. # This is now
  146. # 41fc52:   eb 42                   jmp    0x41fc96
  147. # This was hand-coded assembly, figure it out if you have to.
  148. WINDOWS_MULTIPLE_GLITCH_EXTRA = "\x83\xfe\x09\x74\x58\x83\xfe\x07\x74\x53\x8b\xcf\xe8\xeb\xe6\xff\xff"
  149. WINDOWS_MULTIPLE_GLITCH_UNPATCHED_START = "\x75\x5d"
  150. WINDOWS_MULTIPLE_GLITCH_UNPATCHED = WINDOWS_MULTIPLE_GLITCH_UNPATCHED_START + WINDOWS_MULTIPLE_GLITCH_EXTRA
  151. WINDOWS_MULTIPLE_GLITCH_PATCHED_START = "\xeb\x42"
  152. WINDOWS_MULTIPLE_GLITCH_PATCHED = WINDOWS_MULTIPLE_GLITCH_PATCHED_START + WINDOWS_MULTIPLE_GLITCH_EXTRA
  153.  
  154.  
  155. ############################################################################################
  156. # LINUX file information.
  157.  
  158. # The actual instruction we want to remove is the following (slightly different for each call)
  159. # 4848c2:   e8 29 9c 13 00          callq  5be4f0 <GetRandomINT>
  160.  
  161. LINUX_64_LARRY_1_EXTRA = "\x66\x81\xa3\xa4\x01\x00\x00\x00\xf0\x48\x8d\xbb\xa0\x00\x00\x00"
  162. LINUX_64_LARRY_2_EXTRA = "\xf3\x0f\x2a\xc0\xf3\x0f\x59\x05\xf9\xcb\x13\x00"
  163. LINUX_64_LARRY_3_EXTRA = "\x48\x8b\x3d\x31\x8d\x39\x00\x41\x89\xc4\xbe\x01\x00\x00\x00"
  164. LINUX_64_LARRY_4_EXTRA = "\xf3\x0f\x2a\xc0\xf3\x0f\x59\x05\xe5\xca\x13\x00"
  165. LINUX_64_LARRY_5_EXTRA = "\x83\xf8\x32\x0f\x8f\x27\x04\x00\x00\xc7\x83\xf8\x00\x00\x00\x04"
  166. LINUX_64_LARRY_6_EXTRA = "\x83\xf8\x31\x0f\x8e\xa8\x02\x00\x00\xc7\x83\xf8\x00\x00\x00\x08"
  167.  
  168. LINUX_64_LARRY_1_UNPATCHED_START = "\xe8\x29\x9c\x13\x00"
  169. LINUX_64_LARRY_2_UNPATCHED_START = "\xe8\x85\x9b\x13\x00"
  170. LINUX_64_LARRY_3_UNPATCHED_START = "\xe8\x58\x9b\x13\x00"
  171. LINUX_64_LARRY_4_UNPATCHED_START = "\xe8\x71\x9a\x13\x00"
  172. LINUX_64_LARRY_5_UNPATCHED_START = "\xe8\x80\x99\x13\x00"
  173. LINUX_64_LARRY_6_UNPATCHED_START = "\xe8\x1e\x8d\x13\x00"
  174.  
  175. LINUX_64_UNPATCHED_LARRY_1 = LINUX_64_LARRY_1_UNPATCHED_START + LINUX_64_LARRY_1_EXTRA
  176. LINUX_64_UNPATCHED_LARRY_2 = LINUX_64_LARRY_2_UNPATCHED_START + LINUX_64_LARRY_2_EXTRA
  177. LINUX_64_UNPATCHED_LARRY_3 = LINUX_64_LARRY_3_UNPATCHED_START + LINUX_64_LARRY_3_EXTRA
  178. LINUX_64_UNPATCHED_LARRY_4 = LINUX_64_LARRY_4_UNPATCHED_START + LINUX_64_LARRY_4_EXTRA
  179. LINUX_64_UNPATCHED_LARRY_5 = LINUX_64_LARRY_5_UNPATCHED_START + LINUX_64_LARRY_5_EXTRA
  180. LINUX_64_UNPATCHED_LARRY_6 = LINUX_64_LARRY_6_UNPATCHED_START + LINUX_64_LARRY_6_EXTRA
  181.  
  182.  
  183. # Here the magic happens, the replacement call values. Select whatever generates 3 cycles.
  184. LINUX_64_LARRY_RETURN_1 = 1000
  185. LINUX_64_LARRY_RETURN_2 = 1000
  186. LINUX_64_LARRY_RETURN_3 = 10
  187. LINUX_64_LARRY_RETURN_4 = 1000
  188. LINUX_64_LARRY_RETURN_5 = 1000
  189. LINUX_64_LARRY_RETURN_6 = 10
  190.  
  191. LINUX_64_LARRY_1_PATCHED_START = create_mov_instruction(LINUX_64_LARRY_RETURN_1)
  192. LINUX_64_LARRY_2_PATCHED_START = create_mov_instruction(LINUX_64_LARRY_RETURN_2)
  193. LINUX_64_LARRY_3_PATCHED_START = create_mov_instruction(LINUX_64_LARRY_RETURN_3)
  194. LINUX_64_LARRY_4_PATCHED_START = create_mov_instruction(LINUX_64_LARRY_RETURN_4)
  195. LINUX_64_LARRY_5_PATCHED_START = create_mov_instruction(LINUX_64_LARRY_RETURN_5)
  196. LINUX_64_LARRY_6_PATCHED_START = create_mov_instruction(LINUX_64_LARRY_RETURN_6)
  197.  
  198. LINUX_64_PATCHED_LARRY_1 = LINUX_64_LARRY_1_PATCHED_START + LINUX_64_LARRY_1_EXTRA
  199. LINUX_64_PATCHED_LARRY_2 = LINUX_64_LARRY_2_PATCHED_START + LINUX_64_LARRY_2_EXTRA
  200. LINUX_64_PATCHED_LARRY_3 = LINUX_64_LARRY_3_PATCHED_START + LINUX_64_LARRY_3_EXTRA
  201. LINUX_64_PATCHED_LARRY_4 = LINUX_64_LARRY_4_PATCHED_START + LINUX_64_LARRY_4_EXTRA
  202. LINUX_64_PATCHED_LARRY_5 = LINUX_64_LARRY_5_PATCHED_START + LINUX_64_LARRY_5_EXTRA
  203. LINUX_64_PATCHED_LARRY_6 = LINUX_64_LARRY_6_PATCHED_START + LINUX_64_LARRY_6_EXTRA
  204.  
  205. LINUX_64_PATCHED_LARRY_STRINGS = [LINUX_64_PATCHED_LARRY_1, LINUX_64_PATCHED_LARRY_2,
  206.             LINUX_64_PATCHED_LARRY_3, LINUX_64_PATCHED_LARRY_4,
  207.             LINUX_64_PATCHED_LARRY_5, LINUX_64_PATCHED_LARRY_6]
  208. LINUX_64_UNPATCHED_LARRY_STRINGS = [LINUX_64_UNPATCHED_LARRY_1, LINUX_64_UNPATCHED_LARRY_2,
  209.             LINUX_64_UNPATCHED_LARRY_3, LINUX_64_UNPATCHED_LARRY_4,
  210.             LINUX_64_UNPATCHED_LARRY_5, LINUX_64_UNPATCHED_LARRY_6]
  211.  
  212.  
  213.  
  214. def write_instruction(open_file, position, instruction):
  215.     """Writes the instruct at the specified position of the file."""
  216.     open_file.seek(position)
  217.     open_file.write(instruction)
  218.     open_file.flush()
  219.  
  220.  
  221.  
  222. def check_for_patched_larry(contents):
  223.     """Checks the contents of the file for linux/windows patched and unpatched larry instructions.
  224.    Returns (string, [location1, location2, location3, location4, location5, location6])
  225.    string can be LINUX_64_LARRY_STRING, LINUX_64_NO_LARRY_STRING, WINDOWS_LARRY_STRING,
  226.    WINDOWS_NO_LARRY_STRING, UNKNOWN_LARRY_STRING
  227.    If UNKNOWN_LARRY_STRING then it is an empty list.
  228.    """
  229.     results = check_for_strings(contents, LINUX_64_PATCHED_LARRY_STRINGS)
  230.     if results[0]: # Found all of the strings.
  231.         return (LINUX_64_LARRY_STRING, results[1])
  232.    
  233.     results = check_for_strings(contents, LINUX_64_UNPATCHED_LARRY_STRINGS)
  234.     if results[0]: # Found all of the strings.
  235.         return (LINUX_64_NO_LARRY_STRING, results[1])
  236.    
  237.     results = check_for_strings(contents, WINDOWS_PATCHED_LARRY_STRINGS)
  238.     if results[0]: # Found all of the strings.
  239.         return (WINDOWS_LARRY_STRING, results[1])
  240.    
  241.     results = check_for_strings(contents, WINDOWS_UNPATCHED_LARRY_STRINGS)
  242.     if results[0]: # Found all of the strings.
  243.         return (WINDOWS_NO_LARRY_STRING, results[1])
  244.    
  245.     # Couldn't find any of the correct results, so...
  246.     return (UNKNOWN_LARRY_STRING, [])
  247.  
  248.  
  249.  
  250. def check_for_patched_glitch(contents):
  251.     """Checks the contents of the file for windows patched and unpatched glitch instructions.
  252.    Returns (string, location)
  253.    string can be WINDOWS_NO_GLITCH_STRING, WINDOWS_GLITCH_STRING
  254.    If UNKNOWN_GLITCH_STRING then location is None
  255.    """
  256.     location = contents.find(WINDOWS_GLITCH_PATCHED)
  257.     if location != -1: # Found this string.
  258.         return (WINDOWS_GLITCH_STRING, location)
  259.    
  260.     location = contents.find(WINDOWS_GLITCH_UNPATCHED)
  261.     if location != -1: # Found this string.
  262.         return (WINDOWS_NO_GLITCH_STRING, location)
  263.    
  264.     # Couldn't find any of the correct results, so...
  265.     return (UNKNOWN_GLITCH_STRING, None)
  266.  
  267.  
  268.    
  269. def check_for_patched_multiple_glitch(contents):
  270.     """Checks the contents of the file for windows patched and unpatched MULTIPLE_GLITCH instructions.
  271.    Returns (string, location)
  272.    string can be WINDOWS_NO_MULTIPLE_GLITCH_STRING, WINDOWS_MULTIPLE_GLITCH_STRING
  273.    If UNKNOWN_MULTIPLE_GLITCH_STRING then location is None
  274.    """
  275.     location = contents.find(WINDOWS_MULTIPLE_GLITCH_PATCHED)
  276.     if location != -1: # Found this string.
  277.         return (WINDOWS_MULTIPLE_GLITCH_STRING, location)
  278.    
  279.     location = contents.find(WINDOWS_MULTIPLE_GLITCH_UNPATCHED)
  280.     if location != -1: # Found this string.
  281.         return (WINDOWS_NO_MULTIPLE_GLITCH_STRING, location)
  282.    
  283.     # Couldn't find any of the correct results, so...
  284.     return (UNKNOWN_MULTIPLE_GLITCH_STRING, None)
  285.  
  286.  
  287.  
  288. def check_for_strings(contents, strings):
  289.     """Checks for strings in contents. If any not there returns (False,)
  290.    otherwise if all are there returns (True, [location for string in strings])
  291.    """
  292.     results = []
  293.     for string in strings:
  294.         location = contents.find(string)
  295.         if location == -1: # String wasn't found in file.
  296.             return (False,)
  297.         results.append(location)
  298.     return (True, results)
  299.  
  300.  
  301.  
  302. def unpatch_glitch(open_file, os, position):
  303.     """os is either "linux_64" or "windows", positions is a list of positions."""
  304.     if os == "windows":
  305.         write_instruction(open_file, position, WINDOWS_GLITCH_UNPATCHED_START)
  306.    
  307.    
  308.    
  309. def patch_glitch(open_file, os, position):
  310.     """os is either "linux_64" or "windows", positions is a list of positions."""
  311.     if os == "windows":
  312.         write_instruction(open_file, position, WINDOWS_GLITCH_PATCHED_START)
  313.  
  314.  
  315.    
  316. def unpatch_multiple_glitch(open_file, os, position):
  317.     """os is either "linux_64" or "windows", positions is a list of positions."""
  318.     if os == "windows":
  319.         write_instruction(open_file, position, WINDOWS_MULTIPLE_GLITCH_UNPATCHED_START)
  320.  
  321.  
  322.    
  323. def patch_multiple_glitch(open_file, os,position):
  324.     """os is either "linux_64" or "windows", positions is a list of positions."""
  325.     if os == "windows":
  326.         write_instruction(open_file, position, WINDOWS_MULTIPLE_GLITCH_PATCHED_START)
  327.    
  328.    
  329.    
  330. def unpatch_larry(open_file, os, positions):
  331.     """os is either "linux_64" or "windows", positions is a list of positions."""
  332.     if os == "linux_64":
  333.         write_instruction(open_file, positions[0], LINUX_64_LARRY_1_UNPATCHED_START)
  334.         write_instruction(open_file, positions[1], LINUX_64_LARRY_2_UNPATCHED_START)
  335.         write_instruction(open_file, positions[2], LINUX_64_LARRY_3_UNPATCHED_START)
  336.         write_instruction(open_file, positions[3], LINUX_64_LARRY_4_UNPATCHED_START)
  337.         write_instruction(open_file, positions[4], LINUX_64_LARRY_5_UNPATCHED_START)
  338.         write_instruction(open_file, positions[5], LINUX_64_LARRY_6_UNPATCHED_START)
  339.    
  340.     elif os == "windows":
  341.         write_instruction(open_file, positions[0], WINDOWS_LARRY_1_UNPATCHED_START)
  342.         write_instruction(open_file, positions[1], WINDOWS_LARRY_2_UNPATCHED_START)
  343.         write_instruction(open_file, positions[2], WINDOWS_LARRY_3_UNPATCHED_START)
  344.         write_instruction(open_file, positions[3], WINDOWS_LARRY_4_UNPATCHED_START)
  345.         write_instruction(open_file, positions[4], WINDOWS_LARRY_5_UNPATCHED_START)
  346.         write_instruction(open_file, positions[5], WINDOWS_LARRY_6_UNPATCHED_START)
  347.        
  348.        
  349.        
  350. def patch_larry(open_file, os, positions):
  351.     """os is either "linux_64" or "windows", positions is a list of positions."""
  352.     if os == "linux_64":
  353.         write_instruction(open_file, positions[0], LINUX_64_LARRY_1_PATCHED_START)
  354.         write_instruction(open_file, positions[1], LINUX_64_LARRY_2_PATCHED_START)
  355.         write_instruction(open_file, positions[2], LINUX_64_LARRY_3_PATCHED_START)
  356.         write_instruction(open_file, positions[3], LINUX_64_LARRY_4_PATCHED_START)
  357.         write_instruction(open_file, positions[4], LINUX_64_LARRY_5_PATCHED_START)
  358.         write_instruction(open_file, positions[5], LINUX_64_LARRY_6_PATCHED_START)
  359.    
  360.     elif os == "windows":
  361.         write_instruction(open_file, positions[0], WINDOWS_LARRY_1_PATCHED_START)
  362.         write_instruction(open_file, positions[1], WINDOWS_LARRY_2_PATCHED_START)
  363.         write_instruction(open_file, positions[2], WINDOWS_LARRY_3_PATCHED_START)
  364.         write_instruction(open_file, positions[3], WINDOWS_LARRY_4_PATCHED_START)
  365.         write_instruction(open_file, positions[4], WINDOWS_LARRY_5_PATCHED_START)
  366.         write_instruction(open_file, positions[5], WINDOWS_LARRY_6_PATCHED_START)
  367.  
  368.  
  369.        
  370. class Patcher(tk.Frame):
  371.     def __init__(self):
  372.         tk.Frame.__init__(self, None)
  373.         self.grid()
  374.         self.master.title("SMB Patcher - d265f27")
  375.         self.file = None
  376.         self.larry = None
  377.         self.glitch = None
  378.         self.multiple_glitch = None
  379.         self.populateWindow()
  380.  
  381.        
  382.     def populateWindow(self):
  383.         self.label = tk.Label(self, text=NO_EXECUTABLE_FILE_STRING)
  384.         self.label.pack(padx=5, pady=5)
  385.         self.selectFileButton = tk.Button(self, text="Choose executable", command=self.getFilename)
  386.         self.selectFileButton.pack(padx=5, pady=5)
  387.        
  388.         self.patchLarryFrame = tk.Frame(self)
  389.         self.patchLarryLabel = tk.Label(self.patchLarryFrame, text="Remove Larry RNG")
  390.         self.patchLarryLabel.pack(padx=5, pady=5, side=tk.LEFT)
  391.         self.patchLarryButton = tk.Button(self.patchLarryFrame, text="Patch", command=self.patchLarry, state='disabled')
  392.         self.patchLarryButton.pack(padx=5, pady=5, side=tk.LEFT)
  393.         self.unpatchLarryButton = tk.Button(self.patchLarryFrame, text="Reset", command=self.unpatchLarry, state='disabled')
  394.         self.unpatchLarryButton.pack(padx=5, pady=5, side=tk.RIGHT)
  395.         self.patchLarryFrame.pack(padx=5, pady=5)
  396.        
  397.         self.patchGlitchFrame = tk.Frame(self)
  398.         self.patchGlitchLabel = tk.Label(self.patchGlitchFrame, text="Remove Glitch Girl RNG")
  399.         self.patchGlitchLabel.pack(padx=5, pady=5, side=tk.LEFT)
  400.         self.patchGlitchButton = tk.Button(self.patchGlitchFrame, text="Patch", command=self.patchGlitch, state='disabled')
  401.         self.patchGlitchButton.pack(padx=5, pady=5, side=tk.LEFT)
  402.         self.unpatchGlitchButton = tk.Button(self.patchGlitchFrame, text="Reset", command=self.unpatchGlitch, state='disabled')
  403.         self.unpatchGlitchButton.pack(padx=5, pady=5, side=tk.RIGHT)
  404.         self.patchGlitchFrame.pack(padx=5, pady=5)
  405.        
  406.         self.patchMultipleGlitchFrame = tk.Frame(self)
  407.         self.patchMultipleGlitchLabel = tk.Label(self.patchMultipleGlitchFrame, text="Ignore GG Spawn requirements")
  408.         self.patchMultipleGlitchLabel.pack(padx=5, pady=5, side=tk.LEFT)
  409.         self.patchMultipleGlitchButton = tk.Button(self.patchMultipleGlitchFrame, text="Patch", command=self.patchMultipleGlitch, state='disabled')
  410.         self.patchMultipleGlitchButton.pack(padx=5, pady=5, side=tk.LEFT)
  411.         self.unpatchMultipleGlitchButton = tk.Button(self.patchMultipleGlitchFrame, text="Reset", command=self.unpatchMultipleGlitch, state='disabled')
  412.         self.unpatchMultipleGlitchButton.pack(padx=5, pady=5, side=tk.RIGHT)
  413.         self.patchMultipleGlitchFrame.pack(padx=5, pady=5)
  414.        
  415.    
  416.     def reset_info(self):
  417.         if self.file is not None:
  418.             self.file.seek(0)
  419.             self.contents = self.file.read()
  420.             self.larry = check_for_patched_larry(self.contents)
  421.             self.glitch = check_for_patched_glitch(self.contents)
  422.             self.multiple_glitch = check_for_patched_multiple_glitch(self.contents)
  423.             self.label['text'] = self.larry[0] + '\n' + self.glitch[0] + '\n' + self.multiple_glitch[0]
  424.            
  425.             # Update the buttons.
  426.             if self.larry[0] != UNKNOWN_LARRY_STRING:
  427.                 self.patchLarryButton['state'] = tk.NORMAL
  428.                 self.unpatchLarryButton['state'] = tk.NORMAL
  429.             else:
  430.                 self.patchLarryButton['state'] = tk.DISABLED
  431.                 self.unpatchLarryButton['state'] = tk.DISABLED
  432.            
  433.             if self.glitch[0] != UNKNOWN_GLITCH_STRING:
  434.                 self.patchGlitchButton['state'] = tk.NORMAL
  435.                 self.unpatchGlitchButton['state'] = tk.NORMAL
  436.             else:
  437.                 self.patchGlitchButton['state'] = tk.DISABLED
  438.                 self.unpatchGlitchButton['state'] = tk.DISABLED
  439.            
  440.             if self.multiple_glitch[0] != UNKNOWN_MULTIPLE_GLITCH_STRING:
  441.                 self.patchMultipleGlitchButton['state'] = tk.NORMAL
  442.                 self.unpatchMultipleGlitchButton['state'] = tk.NORMAL
  443.             else:
  444.                 self.patchMultipleGlitchButton['state'] = tk.DISABLED
  445.                 self.unpatchMultipleGlitchButton['state'] = tk.DISABLED
  446.         else:
  447.             self.patchMultipleGlitchButton['state'] = tk.DISABLED
  448.             self.unpatchMultipleGlitchButton['state'] = tk.DISABLED
  449.             self.patchGlitchButton['state'] = tk.DISABLED
  450.             self.unpatchGlitchButton['state'] = tk.DISABLED
  451.             self.patchLarryButton['state'] = tk.DISABLED
  452.             self.unpatchLarryButton['state'] = tk.DISABLED
  453.             self.label['text'] = NO_EXECUTABLE_FILE_STRING
  454.  
  455.  
  456.     def getFilename(self):
  457.         if self.file is not None:
  458.             self.file.close()
  459.         self.file = tkFileDialog.askopenfile(mode='r+b', parent=self, title='Select SMB Executable')
  460.         self.reset_info()
  461.  
  462.                
  463.     def patchLarry(self):
  464.         if self.larry[0] == LINUX_64_LARRY_STRING or self.larry[0] == LINUX_64_NO_LARRY_STRING:
  465.             patch_larry(self.file, "linux_64", self.larry[1])
  466.         if self.larry[0] == WINDOWS_LARRY_STRING or self.larry[0] == WINDOWS_NO_LARRY_STRING:
  467.             patch_larry(self.file, "windows", self.larry[1])
  468.         self.reset_info()
  469.  
  470.  
  471.     def unpatchLarry(self):
  472.         if self.larry[0] == LINUX_64_LARRY_STRING or self.larry[0] == LINUX_64_NO_LARRY_STRING:
  473.             unpatch_larry(self.file, "linux_64", self.larry[1])
  474.         if self.larry[0] == WINDOWS_LARRY_STRING or self.larry[0] == WINDOWS_NO_LARRY_STRING:
  475.             unpatch_larry(self.file, "windows", self.larry[1])
  476.         self.reset_info()
  477.  
  478.        
  479.     def patchGlitch(self):
  480.         if self.glitch[0] == WINDOWS_GLITCH_STRING or self.glitch[0] == WINDOWS_NO_GLITCH_STRING:
  481.             patch_glitch(self.file, "windows", self.glitch[1])
  482.         self.reset_info()
  483.  
  484.  
  485.     def unpatchGlitch(self):
  486.         if self.glitch[0] == WINDOWS_GLITCH_STRING or self.glitch[0] == WINDOWS_NO_GLITCH_STRING:
  487.             unpatch_glitch(self.file, "windows", self.glitch[1])
  488.         self.reset_info()
  489.  
  490.  
  491.     def patchMultipleGlitch(self):
  492.         if self.multiple_glitch[0] == WINDOWS_MULTIPLE_GLITCH_STRING or self.multiple_glitch[0] == WINDOWS_NO_MULTIPLE_GLITCH_STRING:
  493.             patch_multiple_glitch(self.file, "windows", self.multiple_glitch[1])
  494.         self.reset_info()
  495.  
  496.  
  497.     def unpatchMultipleGlitch(self):
  498.         if self.multiple_glitch[0] == WINDOWS_MULTIPLE_GLITCH_STRING or self.multiple_glitch[0] == WINDOWS_NO_MULTIPLE_GLITCH_STRING:
  499.             unpatch_multiple_glitch(self.file, "windows", self.multiple_glitch[1])
  500.         self.reset_info()
  501.  
  502.  
  503. if __name__ == "__main__":
  504.     patcher = Patcher()
  505.     patcher.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement