Jump to content

CmP

Contributor
  • Posts

    640
  • Joined

  • Last visited

  • Days Won

    43

Posts posted by CmP

  1. There is good chance that in some cases it may work by allocating as many pages as needed one after another. Example implementation: 

    local PAGE_SIZE = 0x1000
    function allocateConsecutivePages(count, mode, address)
      count = count or 1
      mode = mode or gg.PROT_READ | gg.PROT_EXEC
      address = address or 0
      local firstPageAddress = gg.allocatePage(mode, address)
      if type(firstPageAddress) == "string" then
        return firstPageAddress
      end
      for i = 1, count - 1 do
        local desiredPageAddress = firstPageAddress + i * PAGE_SIZE
        local pageAddress = gg.allocatePage(mode, desiredPageAddress)
        if pageAddress ~= desiredPageAddress then
          -- failed to allocate page right after previous one, handle as needed
        end
      end
      return firstPageAddress
    end
  2. Make first operand floating-point by multiplying 1.0 by it, that way all calculations will be with floating-point values and you will get approximate result.

    mpy = 1.0 * tonumber(input[1]) * tonumber(input1[1])
  3. 55 minutes ago, _yourram said:

    in this

    It's done exactly as in his example. For your code it may be: 

    gg.clearResults()
    gg.searchNumber("-7041975695332343808", 32)
    gg.refineNumber("-7041975695332343808", 32)
    local results = gg.getResults(10)
    gg.clearResults()
    local values = {}
    for i, v in ipairs(results) do
      values[i] = {address = v.address, flags = 16, value = "100", name = "Custom name"}
    end
    gg.setValues(values)
    gg.addListItems(values)
  4. 5 minutes ago, nok1a said:

    How you found the key?

    Checked implementation of "GetTripleDESCryptoServiceProvider" method that shows how key is derived from "KEY" constant: 

    image.thumb.png.5efc171ffe51de5eeb0103e581f46147.png

    14 minutes ago, nok1a said:

    but i got an error that im using invalid characters

    Because one can't just convert binary data to text and back and expect it to work, that leads to information loss. Use representation that is suitable for binary data. Or use a tool that allows to perform multiple transformations without a need for intermediate representations of data between steps, like the above-mentioned CyberChef.

  5. As for encoding of data that the game uses in preferences (and not only), dump with meaningful names also significantly simplifies research, revealing most of information that needs to be known.

    First step for decoding, that is specific to data in shared preferences, is mentioned in first post of the topic - URL decoding. Then, after base64 decoding, the data needs to be decrypted with Triple DES in ECB mode with 128-bit key "8a76f557475b615a6dcaedeaadd4d27b" (bytes of the key in hex). The result is also base64 encoded, so it needs to be decoded and the last step is to decompress the data as gzip. Below is a CyberChef recipe that implements the decoding: 
    https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',false,true)Triple_DES_Decrypt({'option':'Hex','string':'8a76f557475b615a6dcaedeaadd4d27b'},{'option':'Hex','string':''},'ECB','Raw','Raw')From_Base64('A-Za-z0-9%2B/%3D',false,true)Gunzip()

    And to illustrate it with examples, value for level 5 from topic's first post after decoding is: 

    {"CheckSum":"1EBXq7XeVC5e6TxnIVs/T9kE2J8rLG9IeYdOBc3Nxs9INiuzkhi6urMRRl858UeQdgjO1dLqpfw=","Offset":620,"Value":625}

    and value for level 6 after decoding is:

    {"CheckSum":"1EBXq7XeVC5e6TxnIVs/T9kE2J8rLG9IOjAKjtrE26cgX17n25az4rF8y2+JN4AVv8YyOpD9PI8AmbJGj0p2sw==","Offset":-836,"Value":-830}

    both of which are JSON serializations of structures of "SafeInt" type that the game uses for values that it needs to protect.

  6. 47 minutes ago, nok1a said:

    But why would they have it in process memory if they already have it in the shared pref?

    Because shared preferences is merely a way of preserving data between different runs of application. There is no way to read/write value from/to shared preferences without having it in process memory.

    54 minutes ago, nok1a said:

    Not to sure how you found that out, may i know where in dump you see that it says both encrypted and unencrypted exist?

    Search for fields named "currentAdventureLevel":

    image.thumb.png.359610f54c2e9d3857ae57b24c498ef6.png

    57 minutes ago, nok1a said:

    As far i understand my GG search skill the dump doesn't usually provide me more advantage in finding something then i would without.

    When names of things are not obfuscated, data from the dump provides everything one needs to know to find basically any value in scope of (used by) libil2cpp.so.

  7. I recommend you to grab jadx (or other similar tool) and check how those functions are implemented in GG. There you will also find confirmation that "gg.internal3" and "gg.searchPointer" do exactly the same. If there will be difficulties, ask here or in new topic.

  8. This function has been later made available as part of GG public APIsearchPointer. "gg.internal3" and "gg.searchPointer" are exactly the same function, it's just that it was first an experiment, so started as internal function. By the time of last update of chainer script, "searchPointer" function hasn't existed yet, that's why it isn't used there.

  9. 7 hours ago, nok1a said:

    I am not sure if it would be more easy to do it in process memory. If it is a method of a class then i would not say it is easy, at least for my opinion because i never edit methods since the results after editing usually don´t make sense to me.

    Didn't mean modifying the code, meant the regular GG-way of modifying the value. The only challenge here may be that the value is encrypted, so need to figure out how it works first. Though, I am not sure that it's encrypted value that needs to be modified, since according to the dump value of level exists in both encrypted and unencrypted forms.

    7 hours ago, nok1a said:

    How so not?

    Because finding the value in process memory doesn't require figuring out how it is stored in preferences.

    7 hours ago, nok1a said:

    But if i need to dump the game for find it then i will do that.

    I am somewhat surprised that you haven't checked it as one of the first things, since I see it as the "usual way" of finding desired values in Unity games.

  10. On 11/1/2023 at 10:07 PM, nok1a said:

    I want to locate the level value in the com.unicostudio.gemdoku.v2.playerprefs.xml file so i can edit it with GG

    That doesn't require doing anything with preferences file though and in this case it seems easier to do it in process memory.

    But if I understood correctly, you are researching how storing data in preferences works in case of this game. If that's so, start by doing the usual analysis of Unity games. Get the dump, open dummy dlls in dnSpy, look for things with relevant names within Assembly-CSharp.dll. Then check how those things are implemented in libil2cpp.so. First step should give a surface-level understanding of what's going on there. Second step will provide you with particular answers on how exactly it works.

  11. 39 minutes ago, adhammogza said:

    My brother, I ask you to modify the game for us and give it to us without a protection system

    That's way too unrealistic thing to ask, it requires decent qualification and serious investments of time. The way it can work for you is if someone shares which tools to use and how to not get detected, so it makes more sense to ask for that.

  12. Another typical mistake that causes such error is wrong usage of returned value of "gg.choice" (or "gg.alert") function. Example of wrong and correct usage: 

    local choice = gg.choice({"Option 1", "Option 2"})
    
    -- Wrong usage, returned value is a number, not table
    if choice[1] == 1 then
      print("Option 1 has been chosen")
    end
    
    -- Correct usage
    if choice == 1 then
      print("Option 1 has been chosen")
    end
  13. There are no issues with initial version of your code, it correctly sets value of S0 register to 0.06. It may be that you just need different value to make the character run slower. Does setting the value to 2 increase movement speed or decrease?

  14. From the documentation

    Quote

    Math is different from regular Lua. For binary operations, the first operand determines the type of result. For example,
    3 / 2.0 will be 1, but 3.0 / 2.0 will be 1.5;
    3 + 2.5 will be 5, but 2.5 + 3 will be 5.5.

    So make sure to make first operand float, for example like: 

    local fileSizeInMB = 1.0 * downloadedFileSizeInBytes / (1000 * 1000)
  15. For anyone to possibly be able to help you with your case it is required to specify name of the game and which value you need to track there. Once this is known, one may be able to investigate how to find that value in that particular game in one search or without searches at all by following pointers. "Tracking" can then be implemented as finding the value each time when it's needed.

  16. 6 hours ago, Count_Nosferatu said:

    Why are they doing this?

    That's just code produced by script recording feature. Supposedly, when recording script, call to "processResume" function is inserted each time user returns from GG to game.

  17. Again, the same reason, function "BP1" needs to be defined before it is called. If you don't want to reorder all of the functions, then moving block of code from lines 135-143 to the end of the file may work.

  18. 6 hours ago, SamePerson said:

    I got an error at line 92

    Because you need to define the functions before calling them as has been mentioned in the comment in the code above. For example: 

    function HOME1()
      -- ...
    end
    
    HOME1()

    And not: 

    HOME1()
    
    function HOME1()
      -- ...
    end
  19. I guess you should use "versionName" field for that: 

    -- ...
    
    if v.versionName == VN1 then
      HOME1() -- Functions HOME1, HOME2, HOME3 need to be defined before they are used
    elseif v.versionName == VN2 then
      HOME2()
    elseif v.versionName == VN3 then
      HOME3()
    else
      os.exit()
    end
  20. This merely means that GG hasn't correctly identified that libraries belong to the application, process of which is selected. It doesn't affect anything other than how GG classifies the regions. The regions can still be found manually and from script just fine without relying on region being classified as "Xa", "Cd", etc.

×
×
  • 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.