Jump to content

HorridModz

Contributor
  • Posts

    323
  • Joined

  • Last visited

  • Days Won

    11

Everything posted by HorridModz

  1. Oops sorry, wrong link. Here you go. Anyway, I found the keystone / capstone modes for x86 and x86_64. So I'll go update the tool right now. Here is the new version! Took 5 hours xD. For your needs, this should be a sufficient script, though: OFFSET = "0x970000" LIB_PATH = r"C:\Users\zachy\Downloads\frida-gadget-17.3.2-android-x86.so" ARCHITECTURE = "x86" # OR: "x86_64" from functools import cache import itertools import binascii import keystone import capstone def remove_whitespace(s: str) -> str: return "".join(s.split()) def wraptext(s: str, size: int) -> list[str]: # Thanks to https://stackoverflow.com/questions/9475241/split-string-every-nth-character return [s[i:i + size] for i in range(0, len(s), size)] def getbytes(hexstring: str) -> list[str]: """ Splits a hex string into a list of bytes. Convenient function because it accounts for both whitespace-separated and un-separated hex strings. """ hexstring = remove_whitespace(hexstring) assert len(hexstring) % 2 == 0, "Invalid hex string (odd length)" return wraptext(hexstring, 2) @cache def bytecount(hexstring: str) -> int: """ Counts the number of bytes in a hex string. Very simple function, but improves readability. """ return len(getbytes(hexstring)) @cache def make_ks(architecture: str) -> keystone.Ks: if architecture == "32bit": return keystone.Ks(keystone.KS_ARCH_ARM, keystone.KS_MODE_ARM) elif architecture == "64bit": return keystone.Ks(keystone.KS_ARCH_ARM64, keystone.KS_MODE_LITTLE_ENDIAN) elif architecture == "x86": return keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_32) elif architecture == "x86_64": return keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_64) else: raise ValueError(f"Unrecognized architecture: {architecture}. Only '32bit', '64bit', 'x86', and 'x86_64' are " f"valid strings") @cache def make_cs(architecture: str) -> capstone.Cs: if architecture == "32bit": cs = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_ARM) elif architecture == "64bit": cs = capstone.Cs(capstone.CS_ARCH_ARM64, capstone.CS_MODE_LITTLE_ENDIAN) elif architecture == "x86": cs = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32) elif architecture == "x86_64": cs = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64) else: raise ValueError(f"Unrecognized architecture: {architecture}. Only '32bit', '64bit', 'x86', and 'x86_64' are " f"valid strings") cs.detail = True return cs def offset_to_hex(offset: str, libfile: str, hexbytes: int = 600, sep: str = " "): try: decimal_offset = int(offset, 16) except ValueError: raise ValueError(f"Invalid offset: {offset}. Please provide a hexadecimal value.") with open(libfile, "rb") as lib: # Read certain number of bytes from offset lib.seek(decimal_offset) hexstr = lib.read(hexbytes).hex().upper() if hexstr == "": raise Exception(f"Offset {offset} not found in file {libfile}") return sep.join(getbytes(hexstr)) @cache def armtohex(armcode: str, architecture: str, sep: str = " ", upper: bool = True) -> str: ks = make_ks(architecture) # Convert string of code to list of instructions (split by newline) lines = armcode.split("\n") convertedhexlist = [] for instruction in lines: if instruction.isspace(): continue try: convertedinstruction = ks.asm(instruction, as_bytes=True)[0] convertedhexlist.append(binascii.hexlify(convertedinstruction).decode()) except Exception: raise Exception(f"Failed to assemble ARM opcode: {instruction} with {architecture} " f"architecture. Is the ARM instruction valid? Is the architecture correct?") from None convertedhex = sep.join(convertedhexlist) if upper: convertedhex = convertedhex.upper() return convertedhex @cache def hextoarm(hexstr: str, architecture: str) -> list[str]: if hexstr == "" or hexstr.isspace(): return [] cs = make_cs(architecture) convertedinstructions = [] for insn in cs.disasm(bytearray.fromhex(remove_whitespace(hexstr)), 0x0): op = f"{insn.mnemonic} {insn.op_str}".strip() convertedinstructions.append(op) if not convertedinstructions: raise Exception(f"Failed to disassemble hex: {hexstr} with {architecture} architecture." f" Check that the hex instruction comes from the right lib file at the " f"right offset, and the architecture is correct.") from None return convertedinstructions def is_relative_instruction(instruction: str, architecture): """ Uses capstone and manual heuristics to check if an asm instruction is dynamic. Should work for any architecture! """ cs = make_cs(architecture) # This is annoying. We need to assemble the instruction to hex, then disassemble it again to get capstone info. cs_insns = tuple(cs.disasm(bytearray.fromhex(remove_whitespace(armtohex(instruction, architecture))), 0x0)) if len(cs_insns) != 1: raise Exception(f"Instruction {instruction} is not one instruction (it is {len(cs_insns)}) with architecture" f" {architecture}") cs_insn = cs_insns[0] # noinspection IncorrectFormatting return ("0x" in instruction or "#" in instruction) or (cs_insn.group(capstone.CS_GRP_CALL) or cs_insn.group(capstone.CS_GRP_JUMP) or cs_insn.group(capstone.CS_GRP_BRANCH_RELATIVE)) def generate_aob(hexinstructions: str, architecture: str) -> str: # Convert string of code to list of instructions wildcard_byte = "??" hexlist = [] for instruction in hextoarm(hexinstructions, architecture): instruction_hex = armtohex(instruction, architecture) if instruction_hex == "": continue if is_relative_instruction(instruction, architecture): hexlist.append(" ".join([wildcard_byte] * bytecount(instruction_hex))) else: hexlist.append(instruction_hex) # We want our separator in between every byte, so we do this little maneuver. aob = "".join(hexlist) # Unformatted return " ".join(getbytes(aob)) hexstring = offset_to_hex(OFFSET, LIB_PATH, hexbytes=600) # hexbytes = amount of bytes for AOB print(generate_aob(hexstring, ARCHITECTURE)) x86 turned out to be a huge pain because it has variable-length opcodes and it is harder to detect dynamic ones. But this should work - let me know if it suits you! If you need the dependencies, you can install the tool's requirements.txt.
  2. Yes, of course! But if that's all you want, just copy the few lines of code. In fact, I blogged the creation of the tool and all of the code snippets I used: import itertools import binascii import keystone import capstone def remove_whitespace(s: str) -> str: return "".join(s.split()) def wraptext(s: str, size: int) -> list[str]: # Thanks to https://stackoverflow.com/questions/9475241/split-string-every-nth-character return [s[i:i + size] for i in range(0, len(s), size)] def getbytes(hexstring: str) -> list[str]: """ Splits a hex string into a list of bytes. Convenient function because it accounts for both whitespace-separated and un-separated hex strings. """ hexstring = remove_whitespace(hexstring) assert len(hexstring) % 2 == 0, "Invalid hex string (odd length)" return wraptext(hexstring, 2) def make_ks(architecture: str) -> keystone.Ks: if architecture == "32bit": return keystone.Ks(keystone.KS_ARCH_ARM, keystone.KS_MODE_ARM) elif architecture == "64bit": return keystone.Ks(keystone.KS_ARCH_ARM64, keystone.KS_MODE_LITTLE_ENDIAN) else: raise ValueError(f"Unrecognized architecture: {architecture}. Only '32bit' and '64bit' are valid strings") def make_cs(architecture: str) -> capstone.Cs: if architecture == "32bit": return capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_ARM) elif architecture == "64bit": return capstone.Cs(capstone.CS_ARCH_ARM64, capstone.CS_MODE_LITTLE_ENDIAN) else: raise ValueError(f"Unrecognized architecture: {architecture}. Only '32bit' and '64bit' are valid strings") def armtohex(instruction: str, architecture: str) -> str: ks = make_ks(architecture) convertedhexlist = [] convertedinstruction = ks.asm(instruction, as_bytes=True)[0] return binascii.hexlify(convertedinstruction).decode().upper() def hextoarm(hexinstruction: str, architecture: str) -> list[str]: cs = make_cs(architecture) return next(cs.disasm_lite(bytearray.fromhex(hexinstruction), 0x0))[2:] def generateaobfromarm(armcode: str, architecture: str) -> str: # Convert string of code to list of instructions instructions = list(itertools.chain(*[split1.split(";") for split1 in armcode.split("\n")])) unknownhex = "??" * 4 hexlist = [] for instruction in instructions: if instruction == "" or instruction.isspace(): continue if "0x" in instruction or "#" in instruction: hexlist.append(unknownhex) else: hexlist.append(armtohex(instruction, architecture)) # Hexlist is a list of 4 byte sequences, and we want our separator in between every byte, so we do this little # maneuver. aob = "".join(hexlist) # Unformatted return " ".join(getbytes(aob))
  3. I just noticed your comment about IDA. If your use case is simply to find offsets, this tool does much more than what you're looking for. In terms of the AOB generation, all it does is dumbly check if instructions contains `0x` or `#` (which is not a foolproof system and results in false positives). IDA supports AOB searches, and surely there's better tools out there that you can use to generate AOBs. For instance, https://guidedhacking.com/threads/aob-signature-maker.8524/ seems promising. I'm not trying to discourage you from using my tool, I just want to clarify that it's nothing magical.
  4. Awesome, thanks for the motivation. School started, so I will probably put this off for a while. In the meantime, if you'd like to make the changes yourself, DM me and I can walk you through it. The code is hardcoded for arm64 and arm; that would be a trivial edit - though I don't know whether auto-detection of architecture would be supported (not that this feature matters much).
  5. Yes, this thread is turning into a back-and-forth between you guys rather than a question-and-answer. @Ali7021, these forums are for asking for help for things you can't figure out and getting an answer. If you would like a greater degree of help, perhaps the "Requests" section is better suited. Otherwise, each new question would probably be better off as a new topic if it addresses something entirely different.
  6. That sounds fantastic! I will PM you.
  7. Ah, I see. Still stand by my suggestion though... this is in no way am "unintended effect", and you're more likely to get help somewhere else.
  8. Repeatedly freezing will not fix this. Is the value actually staying the same? If the value is frozen, this tells Gameguardian to constantly set this value back to what you edited it to. It does not stop the game from changing the value, which can cause back-and-forth fighting if both are trying to set the value. You can try to go into Gameguardian' settings and set the freeze interval to 0 (this will make Gameguardian change the frozen value every 0 milliseconds, or as frequently as possible). This setting should be in the Settings for the Game section, if I am not mistaken. It's also possible that the address changes, and the one you freeze stays the same but the game uses another value. Another possibility is that this is not the right vslue at all - perhaps it's a visual value but not the underlying one, or perhaps the real value is encrypted.
  9. Try using the MagiskHide module and HideMyApplist. There are tons of guides online.
  10. I don't get why you can't just try to hide from nmcore. I have no idea, but I'd give the typical Hide Gameguardian from the Game settings / Magisk Hide / HideMyApplist a try.
  11. Working on it. For compatibiliry purposes, I'm making it as a GUI rather than a CLI. It is almost done but is a lot of work. If you really want to, you can download the repository and run it yourself (see usage instructions in the Github repository) - simply instal python and run the cli.py file in termux.
  12. This issue isn't just for Chromebooks; it is a general issue with Android apps. There are several reasons for this; the forums have many threads on it such as this one: app not installed as app isn't compatible with your phone (#azg6l3h) In addition to gameguardian-specific research, you can try researching the general issue ("android app not installed as it is not compatible with your phone") - a Google search will yield lots of suggestions and troubleshooting ideas.
  13. I'm pretty sure Mr. Dragon Star has a guide on Youtube. There are also several scripts.
  14. What is the problem, exactly? Do you have Gameguardian installed? Is it giving you an error message?
  15. Out of curiosity, would you use it if I implemented this? If I had motivation to I would; otherwise I'll just file a Github issue and kick the can down the road .
  16. If the number of chests is server sided, their contents likely are too. As I said before, you can try pausing the game + editing the value between when you find out your reward and when you claim it. Another approach is to search the reward after claiming it and edit + freeze it in the hopes that it will show up next time; again there is no guarantee that this will work. Chests may be a dead end for you.
  17. Can you see the rewards before opening the chest? If not, maybe you can try pausing the game while opening the chest. But if the game generates the chest reward at the same time that you open / claim it, editing it may not be possible without hex patching the function itself. One more idea is to try searching for the chest rewards *after* you open it and editing + freezing the values so you get modified rewards next time.
  18. Besides analyzing the code, there is no real way to know what is server sided and what is client sided. The best way is to try stuff, and if something doesn't work you move on. Unfortunately, modding is often a game of guessing and checking rather than getting what you want on the first try. I am unfamiliar with Virtual Master, but for most Virtual spaces any files will not show up in them. Either download it inside of Virtual Master (go to this post in a web browser, inside of that space) or you can see if there is an option to transfer files.
  19. This should probably go in Help. But anyway - what's the app, and what did you change?
  20. I am confused by what exactly you did - it sounds like you used parallel space on your phone and opened the game with the taskwall on a computer? If this is what you did, it will not work. I don't know exactly how these taskwalls work (you can definitely research it if you wish), but I believe they have several restrictions. One of these is that you must download and play the game on the *same device* as the one you one you initially start the offer on.
  21. Also, another method is to directlly edit those fields you mentioned. Editing fields is doable, but a bit of a pain. Here is a script for doing so: https://hackershouse.tech/feild-offset-finder-game-guardian
  22. Perhaps the game has yet to call the method. Try updating your coins (gaining or spending some).
  23. Thank you for the info! This is very interesting.
  24. Out of curiosity, why have I never seen a script that supports x86 and x64? In fact, as far as I know gameguardian only supports target.isx64 or whatever it is and only supports armv7 / arm64 opcodes, etc. etc. - I'm unaware of Gameguardian supporting these alternative architectures at all. It would be great if you could point to some references for this. Update: hmm the *only* resource I could find for this was a stackoverflow post... https://stackoverflow.com/questions/17770907/is-android-os-only-used-for-arm-cpus
  25. Interesting! I will have to implement that when I get a chance - should be simple. Thanks for the advice. The documentation does say search pattern - it's simply an array of bytes search. The program generates an aob by reading bytes from the function's start offset and keeping the bytes that represent static instructions. Then it generates a group search by converting strings of static bytes into qwords, dwords, etc. This will not work between Architectures. Sadly, as far as I know the instructions aren't one-to-one so "transpiling" the aob to another architecture wouldn't work. Out of curiosity, why have I never seen a script that supports x86 and x64? In fact, as far as I know gameguardian only supports target.isx64 or whatever it is and only supports armv7 / arm64 opcodes, etc. etc. - I'm unaware of Gameguardian supporting these alternative architectures at all. It would be great if you could point to some references for this.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.