-
Posts
255 -
Joined
-
Last visited
-
Days Won
13
Content Type
Profiles
Forums
Downloads
Gallery
Everything posted by XEKEX
-
Using "offset calculator" I go to the address (base addr + offset addr). should give you "PUSH" instruction (-- this will indicate the start of the function ) -- "POP" instruction indicate the end of the function. overwrite the original code won't crush the game if you do it right with the correct instructions. --return 100 as double value instructions are : ~A8 MOVZ X0, #0x5900 -- overwrite push instrunction ( dummy address : 0x0000 ) ~A8 MOVK X0, #0x4000, LSL #16 -- the instruction below push ( dummy address : 0x0004 ) ~A8 MOVK X0, #0x0000, LSL #32 -- etc ( dummy address : 0x0008 ) ~A8 MOVK X0, #0x0000, LSL #48 -- ( dummy address : 0x000C ) ~A8 FMOV D0, X0 ~A8 RET -- 6 (4 bytes address edits ) in total ( look dummy address ) -- the CPU will assume the function body is like after the edit : -- double currentHP () { -- return 100 -- } after you edit these 6 addresses the left over address until POP instructions became code cave you can inject a code in it without using gg.allocatePage() ( some game detect new alloc memory and it force close the game ) note : register X will hold 64 bit values , W will hold 32 bit values
-
godbolt will assume that the code you write is an actuel program it store the double value in memory and then call ldr on it , in arm patching it's different , FMOV it's an FPU mov instruction , we use movk and movz , lsl to modify X0 to the desired hex value then send the X0 to the fpu register. -- Load the lower 16 bits of the value into X0 MOVZ X0, #0x0000 -- Load the next 16 bits of the value into X0, left-shifted by 16 bits MOVK X0, #0x4000, LSL #16 -- Load the next 16 bits of the value into X0, left-shifted by 32 bits MOVK X0, #0x0000, LSL #32 -- Load the upper 16 bits of the value into X0, left-shifted by 48 bits MOVK X0, #0x0000, LSL #48 -- X0 now hold : 0x4040000000000000 -- Copy the value in X0 to D0 FMOV D0, X0 RET here is a better example of using lsl and movk : --X0 = 0x1234567891234567 -- Load the lower 16 bits of the value into X0 (0x0000000000004567) MOVZ X0, #0x4567 -- Load the next 16 bits of the value into X0, left-shifted by 16 bits (0x0000000091234567) MOVK X0, #0x9123, LSL #16 -- Load the next 16 bits of the value into X0, left-shifted by 32 bits (0x0000567891234567) MOVK X0, #0x5678, LSL #32 -- Load the upper 16 bits of the value into X0, left-shifted by 48 bits (0x1234567891234567) MOVK X0, #0x1234, LSL #48
-
LDR will load the register X0 + 0x28 into D0 adding [] will make the value X0 + offset a pointer, D0 will hold the value which this pointer hold *no edits happen* editing get_hp method arm code isn't good in most cases because usally this method related to enemy aswell (creating a god mod will result a god mod for npc aswell ) what access the methods is the class field (the caller (field). X0 will hold the caller address in the original arm code) look into the fields if there is an indice to player even a string searching the class name instead of the method and do some logic in a function to trigger the edit of the player hp only(by matching the player indice). the edit should be just the value no arm patching if the method get_hp in a class specific for player than you can edit the arm code with no problem
-
Only old accounts that abuse this method still got the money , they already patched it. i played this game since 2015 or somthing on facebook (with hack ofc) my acc didn't get ban. last years it does get ban when I try it on mobile and tryed to hack it again I did sevral attempts but all fail so I assume that they calculate the amount of cash that you can obtain for free and how much u perform in app purchase if it doesn't match your acc will trigger ban. this proccess is server side.
-
This is correct for int. you can check GodBolt.org
-
register W will hold 32 bit values and X will hold 64 values , local binary = string.pack("f", 4.0) -- this will convert the float 4 to binary form "f" = float / "d" = double local hex = "" for i = 1, #binary do -- this loop will give us the hex value of the binary above hex = hex .. string.format("%02X", string.byte(string.reverse(binary), i)) end --[[ the final arm code will be : ~A8 MOVK X0, #0x0000, LSL #16 -- LSL will shift our hex value ~A8 MOVK X0, #0x4080, LSL #32 ~A8 FMOV S0 ,X0 ~A8 RET ]] --reply if the code work for you
-
-
-
-
-
nah u just need to dump the lib and the metadata and start hacking the game see the Guide section it will help you alot and use youtube if u stuck on how to hack libil2cpp game
-
Fixed
-
-
Quick Notes: Low Registers (R0 to R7): Accessible by all instructions using general-purpose registers. High Registers (R8 to R12): Accessible by 32-bit instructions specifying a general-purpose register, not all 16-bit instructions. Stack Pointer (R13): Used as the Stack Pointer (SP). Autoaligned to a word, four-byte boundary, ignoring writes to bits [1:0]. Link Register (R14): Subroutine Link Register (LR). Receives return address from PC during Branch and Link (BL) or Branch and Link with Exchange (BLX). Also used for exception return. Treat as a general-purpose register. Program Counter (R15): PC. FPU (Floating Point Unit): Supports single-precision operations - add, subtract, multiply, divide, multiply and accumulate, and square root. Also handles conversions between fixed-point and floating-point formats, and floating-point constant instructions. FPU Registers: Sixteen 64-bit doubleword registers: D0-D15. Thirty-two 32-bit single-word registers: S0-S31. ->Source <- --------------------------------------------------------------------------------------------------------------------------------- In Arm Patching we are using only Low Registers and the FPU. True and false Editing. ~A MOV R0, #1 MOV means Move , by this instruction we are telling the proccessor to move the value 1 to register R0 similar when you assign a variable name : R0 = 1 in most programing languages the true statment always = 1 and the false statment = 0 so #1 = true and #0 = false ~A BX LR BX Means branch exit LR or in another way return the value we stored to the caller. Int Editing : we can use MOV R0, # aswell for the int value but you need to know the integral data types. • byte : Signed: From −128 to 127 : Unsigned: From 0 to 255 we can use MOV here if the int value we want is between -128 and 255 so the instruction will be : ~A MOV R0, #-128 or #255 at max • short : Signed: From −32,768 to 32,767 : Unsigned: From 0 to 65,535 in this case we use MOVW the W stands for Word so same as above the instruction will be : ~A MOVW R0, #−32,768 or #65,535 at max NOTE : • Don't forget to return (~A BX LR) • We can Use MVN which mean Move Negative so the Max Negative Value will be #255 for Byte and MVNW for Short #65,535 (Don't add "-" since we already telling the proccessor we are dealing with negative number) • #value will be converted automatically to hex value in the Register means #8 will be 0x00000008 and so on • Int 32 : Signed: From −2,147,483,648 to 2,147,483,647 : Unsigned: From 0 to 4,294,967,295 the typical DWORD in GG : here we move to the advanced Part of this guide: as I said in the Note above the values are converted in the register automatically to hex so the max value in short in hex will be 0x0000FFFF so we have 4 zero's we can't change in the int 32, in this case we use one more instructon MOVT T stands for Top example : MOVW R0, #22136 -> R0 will be : 0X00005678 MOVT R0 , #4660 -> R0 will be : 0x12345678 So in case of INT32 we need 2 things • Convert the value we want to change to hex value • 3 instruction in total the Same concept here work for QWORD aswell (64 bit) 0x0000000000000001 Note : MVN R0, #2 will change to 0xFFFFFFF2 in hex MOV R0, #2 or MOV R0, #0x2 are the same Float and Double: • Float and Double are IEEE 754 Floating-Point: We need the FPU here and things will get a little bit complicated, • we need 2 or 3 registers in this case R0 , R1 and S0(for float) or D0(for double) Suppose the hex value of this float 12.6 is : 0x4149999A same as the int 32 : ~A MOVW R0, #0x999A (R0 = 0x0000999A) ~A MOVT R0, #0x4149 (R0 now = 0x4149999A) now R0 is set but if we return the value (~A BX LR) the result will be : 1095342490 and we don't want that value we want 12.6 as float (This Doesn't Work Because we didn't tell the proccessor that is a float number) the right way is to use FPU VMOV S15, R0 ( VMOV is the instruction MOV in the FPU : by that instruction we mean move the register value of R0 to the FPU register R15 ) VMOV.F32 S0, S15 (here we are telling the FPU we are dealing with Float number (F32) and move the value from S15 to S0 ) for double we use the same concept except we use F64 instead and register D16 and D0 Float : so the final code will be : ~A MOVW R0, #0x999A (R0 = 0x0000999A) ~A MOVT R0, #0x4149 (R0 = 0x4149999A) ~A VMOV S15, R0 ~A VMOV.F32 S0, S15 ~A BX LR ----------------- Double : For double the hex value of 12.6 is : 0x4029333333333333 (Same Concept for Big Float Number) • Here we use R0, R1 , D0 and D16 • divide the hex value 0x4029333333333333 into 2 part 0x40293333 and 0x33333333 one goes for R0 and the other one goes for R1 Be carful of the placement of the hex value we start from the last 4 to the 1st 4 means we start with 0x3333 -> 0x4029 Use same concept of MOVW and MOVT to get the result. Result: ~A MOVW R0, #0x3333 (R0 = 0x00003333) ~A MOVT R0, #0x3333 (R0 = 0x33333333) ~A MOVW R1, # 0x3333 (R1 = 0x00003333) ~A MOVT R1, #0x4029 (R1 = 0x40293333) ~A VMOV D16, R0, R1 (Move value Of R0 and R1 to register D16 Be Careful here R0 last 8 hex 1st then R1 the top 8 hex) ~A VMOV.F64 D0, D16 (here we use F64 and D0 , and D16 instead of F32 , S0 and S15 because the hex value is 64 bit) ~A BX LR ------ This is How you arm patch bool / int / float / double NOTE : When it comes to function args and returns the only register that give return or args are R0,R1,R2,R3 (and SP) this is why we use R0 and VMOV S15/D16 to S0/D0 ARMv8 : In ARMv8, LSL stands for "Logical Shift Left". It is an instruction used to shift the bits in a register to the left by a specified number of bits, and the bits that are shifted off the left-hand end are discarded. LSL can be used with immediate values or with a register value. The immediate value specifies the number of bits to shift, which can be between 0 and 63. When using a register value, the bottom byte of the register specifies the number of bits to shift Example : Level 1 ) LSL X1, X2, #3 --> Shift the contents of X2 left by 3 bits and store the result in X1 -> In this example, X2 is being multiplied by 8 (since 8 is 2 to the power of 3), and the result is stored in X1. Level 2) MOV and LSL example: MOV X1, #0x10 -->Move the value 0x10 into register X1 LSL X1, X1, #3 --> Shift the contents of X1 left by 3 bits (multiply by 8 ) Level 3) Float Value : 3.14159 / Hex : 0x40490FD0 --Load the value 0x0FD00000 into bits 16-31 of W0 • MOVK W0, #0x0FD0, LSL #16 --> W0 = 0x00000FD0 -- Load the value 0x40490000 into bits 32-47 of W0 • MOVK W0, #0x4049, LSL #32 -> W0 = 0x40490FD0 -- Move the value of W0 into single-precision floating-point register S0 • FMOV S0, W0 --> S0 = 0x40490FD0 (interpreted as a floating-point value) Note : 4 bytes hex (32) value we use register W and for float we use S Level 4 ) Double value : 3.14159 / Hex : 0x400921F9F01B866E MOVK X0, #0xF01B866E, LSL #16 -->X0 = 0x00000000F01B866E MOVK X0, #0x400921F9, LSL #48 -->X0 = 0x400921F9F01B866E FMOV D0, X0 Note: 8 bytes hex (64) value we use register X and for Double we use D NOTE: SAME CONCEPT IN AARCH32 WITH (INT, BOOL, FLOAT, AND DOUBLE) LSL and MOV(Z/K) is the diffrences. PART II (LDR / STR): [STRING] ( NON UNITY GAMES ) Little-endian / Big-endians : LDR and STR are instructions used in ARMv7 and ARMv8 architectures to load and store data from memory. LDR stands for "Load Register" and is used to load a value from memory into a register. The syntax for LDR in ARMv7 and ARMv8 is LDR <Register>, [<Address>] STR stands for "Store Register" and is used to store a value from a register into memory. The syntax for STR in ARMv7 and ARMv8 is STR <Register>, [<Address>] where <Register> is the name of the register to load the value into, and <Address> is the memory address from which to load the value. In both cases, the square brackets around <Address> indicate that the value inside the brackets is a memory address, rather than a register. To load the string 'GG TESTING' into a register, you can use the LDR instruction. Assume the pointer to 'G' is 0x00000004 we can use this address as the base address for the LDR instruction. The instruction for loading the first four characters of the string into a 32-bit register (e.g., R1/X1) would be: • LDR R1/X1, [0x00000004] -- R1/X1 = 'GG T' This instruction loads the 32-bit value at memory address 0x00000004 into R1/X1. Note: Use the Move instructions above (PART I) to assign the value (address) to a register BEFOR USING LDR --> LDR R1/X1, [R0] -- R0 = 0x123456789 ( use MOV to assign the correct address to R0 or X0) To load the entire string into a register, you can use the LDR instruction with a register offset. Assuming the string is stored in consecutive memory locations, we can use the following instruction to load the entire string into a register (e.g., R1/X1) LDR R1/X1, [0x00000004], #10 This instruction loads the 32-bit value at memory address 0x00000004 into R1 and increments the base address by 10 (the length of the string). As a result, the entire string 'GG TESTING' will be loaded into R1. ADVANCED : If 'GG TESTING' is a half-word (i.e., each character is 2 bytes or 16 bits) and the pointer to 'G' is located at memory address 0x0000004 + 0x8, then the instructions for loading the string into a register would be different Dummy memory: 0x0000004 (<-- pointer )= 123 0x0000008 = 21 0x000000C = 9999999 0x0000010 = 'GG' 0x0000014 = ' T' -- with space at the start. 0x0000018 = 'ES' etc.. --> between every byte value ( character ) there is 0 [ example in memory 0x00000010 = 71 (G) <-- byte 0x00000011 = 0 <-- byte 0x00000012 = 71 (G) <-- byte 0x00000013 = 0 <-- byte 0x00000014 = 32 (space) <- byte ] To load the half-word 'GG' into a 32-bit register (e.g., R0/X0), we can use the LDRH instruction as follows: LDRH R0, [0x00000004, 0x8] This instruction loads the 16-bit value at memory address 0x00000010 into the lower 16 bits of R0/X0. Since we want to load the first two characters of the string, we add an offset of 0x8 to the base address. Read more about LDR To load the entire string into a register, we can use the LDRH instruction with a register offset as follows: LDRH R0, [0x00000004, 0x8], #0xC This instruction loads the 16-bit value at memory address 0x00000010 into the lower 16 bits of R1, and increments the base address by 0xC (or 12 bytes) to load the remaining characters of the string. The 'GG TESTING' string has a length of 10 characters, which corresponds to 20 bytes (11 characters x 2 bytes per character), so we need to load 12 bytes in addition to the first 2 bytes to load the entire string. AARCH64 : LDRH --> LDURH (Load Unsigned Halfword with a 64-bit offset) or LDSRH (signed) LDURH W0, [X1, #16] ; Load a halfword from the memory address X1 + 16 into W0 This loads a 16-bit unsigned halfword from the memory address X1 + 16 into the 32-bit register W0. Note that the offset value is added to the base register X1 to form the memory address. Also, because LDURH is an unsigned load instruction, the loaded halfword is zero-extended to 32 bits. NOTE: the LDURH instruction is specific to AArch64 architecture and is not available in AArch32 architecture. STR: STR is used to store the contents of a register into a memory location that is addressed using a base register and an optional offset. The contents of the register are written to the memory location, overwriting any previous data that was stored at that location. -->STR Rd, [Rn {, #offset}] where Rd is the source register whose contents will be stored in memory, Rn is the base register that points to the memory location where the data will be stored, and offset is an optional 32-bit offset that is added to the base register to form the memory address. Example of using the STR instruction to store the contents of R0 register into a memory location: --> STR R0/X0, [R1/X1, #4] ; Store the contents of R0/X1 into the memory location R1/X1 + 4. NOTE : STR Wd, [Xn, #offset], imm | the STR instruction with the imm option is only available in AArch64. |--> Wd/Xd, [Xn, #offset] The imm option allows you to add an immediate value to the offset to form the memory address. The immediate value is sign-extended to 64 bits, shifted left by the scale factor (which is determined by the size of the data being transferred), and then added to the offset. -> STR W0, [X1, #0x100], #0x20 -- This stores the contents of register W0 into the memory location pointed to by register X1 plus 0x100 plus 0x20, overwriting any previous data stored at that location. In AArch32, there is no imm option for the STR instruction. However, you can achieve a similar effect by adding the immediate value to the offset before using it in the instruction. Here's an example: ADD R2, R1, #0x120 --> R2 = R1 + 0x120 STR R0, [R2] --> Store R0 at address R2 Here, the ADD instruction adds the immediate value 0x20 to the base register R1, storing the result in R2. The STR instruction then stores the contents of register R0 into the memory location pointed to by register R2. Note: that the immediate value is added to the offset before using it in the instruction, rather than being added as a separate operand like the imm option in AArch64. --->FOR Using LDR / STR on values just LDR/STR R0/X0, [DESTINATION ADDRESS] Note : Unity games use pointers for the string ----------------------------------------------> Converting Float and Double to Hex <--------------------------------- This is mainly IEEE Standard for Floating-Point Arithmetic. (you can skip this part by using online converter) > You need : • Advanced Lua scripting Knowladge. • Math Knowladge. • Binary 32 and 64 Knowladge. --------------Please read--------------
-
-
open the apk as zip ull find folder called lib if u find libil2cpp then the game use unity engine if u find cocos2D then the game use lua and c if u find UEsomthing then the game use unreal engine some games write their own lib (rare case) the server side hacking is more higher in cocos2d bc they use libC aswell and you can exploit in many ways such as buffer over flow remote code execution and frida use ida or jadx to dump that lib and search for function that encrypt data and hook it with frida use burp suite aswell to intercept server data and decrypt it using frida most cases the game use firebase to transfer data server side + ngnix and the only solution to hack the server side is by brute force ssh and u need powrfull pc to perform that and linux machine using msf console or ghidra and nmap
-
View File Dump.CS to Lua Table This Script will change all the Dump.cs file into new file.lua contain a lua table • remove void function since they act on themself or on the class and no return values • filter all possible function / classes for hack usage • ENUM not included • seal / protected are filterd • filter system and all other dll functions • Work for PC and GG script Note : use the script on PC for faster results + the dump name MUST be "Dump.cs" --Script not Encoded feel free to learn Submitter XEKEX Submitted 01/23/2023 Category Tools
-
Version 1.0.0
1,029 downloads
This Script will change all the Dump.cs file into new file.lua contain a lua table • remove void function since they act on themself or on the class and no return values • filter all possible function / classes for hack usage • ENUM not included • seal / protected / Abstract are filterd • filter system and all other dll functions • Work for PC and GG script Note : use the script on PC for faster results + the dump name MUST be "Dump.cs" --Script not Encoded feel free to learn -
I get it now , anyway your script is similar to elf binary you can research it it might help you
-
lua script runs from top to buttom it won't execute the condition befor the the val get increment also last value in dex won't meet the requirement for the condition this is why u need to put all conditions on top of the loop
-
-
to change 2 values u need to select 2 values u can add the 2ed address by adding new value to your table : arm_True= { ------------- we add new tabe that contain the arm instruction we want [1] = '~A MOV R0, #1', [2] = '~A BX LR', } -- in the table below (base_T) u can save only the address + offset of multiple functions (function a , b , c ,d .. ) base_T = {['address'] = gg.getRangesList('libil2cpp.so')[1].start + offset } -------- we add another table that contain the base address + offset for i = 1 ,#arm_True do ------------ I prefer use for loop this will make changes depending on the number of changes in arm table base_T[i].value = arm_True[i] base_T[i].address + 4 ------------- the 2ed address is always the prev one + 4 end -- if u use the loop above it will change all the functions a,b,c ,d .. to the arm instruction u want (true) without any other coding or searching for every 2ed address gg.setValues(base_T) ----- then we set the values --this method work for 2+ modification --u can also write base_T[1] = .. base_T[2] = .. manually instead -- u can add new index contain the original value in case u want to perform multiple changes base_T = gg.getValues(base) ---- and it's values
-
for i = 1, loop do if valStart >= range[3]["end"] then break ---->>>>>> make the if statment at the start so it won't add some unwanted addresses an cause crush later dex[#dex + 1] = {address = valStart, flags = gg.TYPE_QWORD} valStart = valStart + 0x250 end end
-
You can try to save the the result to a table and use for loop to freeze the values then add update function to that table and it will keep he values freezed : for index,values in pairs(your_table) do your_table[index].freeze = FREEZE_NORMAL (or true idk x) ) end your_table:update = function(self) -- body end