Jump to content

CmP

Contributor
  • Posts

    672
  • Joined

  • Last visited

  • Days Won

    49

Posts posted by CmP

  1. The main issue is with the approach itself. Processing all results/values at once isn't going to work when there are millions of them. There is simply not enough memory that is available to Java part of the application neither to load millions of results at once nor to build a table in Lua script that represents millions of values. The solution is to process results/values in parts. Reasonable choice for part size is around 100k, since in practice GG can load 100k results fine in most cases.

    Another issue is related to efficiency as MAARS also mentioned above. First thing to avoid is using "gg.loadResults" function when it's not necessary. If it's applicable, use searches to get all results for processing, then process them in parts by getting results and removing them after the part is processed. Alternatively build a table with part of values to process, but then don't use results list, proceed to getting/setting values directly using corresponding API functions, then repeat for remaining parts.

  2. 1 hour ago, Ferib said:

    The GG Daemon process was an example and has indeed to be selected

    There is "one small issue" with this example. It implies that GG daemon would attach to itself. Not only it can't work like that, GG also doesn't show it's own daemon in process list (for the aforementioned reason).

    You clearly confused something in this example, but instead of admitting it, you have resorted to suggesting that critique of your example stems from "lack of knowledge". Such desperate attempts to "never make mistakes" is a sign of arrogance and an obstacle that prevents learning from one's own mistakes.

  3. 3 hours ago, Ferib said:

    the GG daemon process is just an example, can be any process

    This example doesn't make sense. Only memory of selected process can be modified. Scripts have no control over which process is selected. So the question remains, what does GG daemon have to do with this?

  4. On 11/20/2022 at 4:38 PM, Ferib said:

    Might as well hook the GG daemon and executed arbitrary code.

    How to "hook the GG daemon" from script for GG? Or what is this supposed to mean? Where in a process that is selected in GG would there be anything related to GG daemon?

    As for executing arbitrary code, the approach from your previous sentence already allows that, but of course code can only be executed in context of the process that is selected in GG. So what does GG daemon have to do with this?

  5. 2 hours ago, MainC said:

    Is saving the Password on a script is more better?

    Having password that is required to execute a script for GG is not a good idea in general, but having limited password (by expiration time, amount of uses or something else) is a faulty one, because the limit can't be enforced anyhow. If a script for GG can be executed once, this is already enough to preserve all of the required data to execute it again unlimited amount of times regardless of password. In other words, password for a script for GG can only work as initial protection: either user doesn't know the password and won't be able to execute the script at all or user knows the password and with certain preparations will have unlimited access to the script after executing it one time.

  6. 1 hour ago, MainC said:

    - Pastebin only accept HTTPS (SSL), entire Payloads are encrypted and not view-able. Safe from Packet Capturers.

    This is absolutely not the case. Here is an example of packet capture application for Android that can show users decrypted contents of HTTPS requests and responses from/to GGhttps://play.google.com/store/apps/details?id=app.greyshirts.sslcapture

    Similarly, there are other applications for Android and a bunch of much more well-known ones for Windows, each of which has this capability.

  7. 45 minutes ago, blocx said:

    omg it still crash game 😕

    There was a mistake in my last example. Edited the post with fixed version, so probably it should work as expected now.

  8. If I understood correctly, it's because you also need to edit next instruction to "RET" for your patch to work as expected. The example above can be modified to do that: 

    local libStartAddress = gg.getRangesList("libil2cpp.so")[2].start
    local targetAddress = libStartAddress + 0x14BB114 
    gg.setValues({
        {address = targetAddress, flags = gg.TYPE_DWORD, value = "~A8 MOV W0, #999"},
        {address = targetAddress + 4, flags = gg.TYPE_DWORD, value = "~A8 RET"}
    })

    Edit: corrected mistake in previous version of the code

  9. 48 minutes ago, blocx said:

    its possible in less complex like this ? :

    Yes, just use that edit string as "value" field. For example: 

    local libStartAddress = gg.getRangesList("libil2cpp.so")[2].start
    local targetAddress = libStartAddress + 0x14BB114 
    gg.setValues({{address = targetAddress, flags = gg.TYPE_DWORD, value = "~A8 MOV W0, #999"}})
  10. 18 hours ago, galih_ken said:

    From here, gameguardian.net. that's why I get confused that everyone doesn't know something is off.

    When GG reinstalls itself, version of the apk is set to a random one. That's where version "239.0" came from in your case.

  11. 17 minutes ago, MonkeySAN said:

    and take credits for it

    In the description of the video there is the following: 

    image.thumb.png.b3b2fc6bd17b208e74b4e1317ca5ca88.png

    So at the very least author of the video has specified who and where originally posted the method. Of course it would be more reasonable to include link to this thread, but at least there is some mention at all.

  12. 13 minutes ago, dolphinorca said:

    and because of the 1024 byte limit

    The idea is to read enough bytes at once and then trim the string to first occurrence of quote character instead of reading one byte at a time until quote character is encountered. Generally, first approach should be better in terms of performance, because each read from memory takes significantly more time than several Lua operations, even if just one byte needs to be read.

    25 minutes ago, dolphinorca said:

    So, I was told the code, but I couldn't get it normally. (You can fix it by changing "local address = results[i].address + 12" to +11. I've noticed it in advance and I don't know why I subtract 1.)

    I thought to add 12 to get position of first byte of the answer that is the next one after last quote character in searched string. I don't immediately see why it doesn't work as expected, but it seems that there is a mistake somewhere and it's fixed by your correction to use "+ 11" instead of "+ 12".

  13. You should also consider refactoring the code to make it simpler and cleaner. For example, your "MENU1" function can be refactored to something like the following: 

    function MENU1()
      gg.setRanges(gg.REGION_ANONYMOUS)
      gg.clearResults()
      gg.searchNumber(':","answer":"', gg.TYPE_BYTE)
      local count = gg.getResultsCount()
      local results = gg.getResults(count)
      local answers = {}
      for i = 1, count, 12 do
        local address = results[i].address + 12
        local maxLength = 1024
        local answer = readBytesToString(address, maxLength)
        answer = answer:match('[^"]*') -- match part up to first quote character
        table.insert(answers, answer)
      end
      for number, answer in ipairs(answers) do
        print(string.format("Answer #%d:", number), answer)
      end
      gg.alert("Answer See [ON]")
    end

    Let me know, if the code above works for you.

  14. To output a string Lua implementation in GG treats it as UTF-8 (by themselves Lua strings are just byte arrays), so reading bytes from memory to Lua string and passing the string to a function that outputs it ("print", "gg.alert", "gg.toast", etc) should be enough to achieve desired result in your case.

    Here is an example of function for reading bytes from memory and constructing string from them: 

    function readBytesToString(address, length)
      local values = {}
      for i = 0, length - 1 do
        values[i] = {address = address + i, flags = gg.TYPE_BYTE}
      end
      values = gg.getValues(values)
      local bytes = {}
      for i, v in ipairs(values) do
        bytes[i] = v.value & 0xFF
      end
      return string.char(table.unpack(bytes))
    end

    Call it with address to read from as first argument and amount of bytes to read as second argument, for example: 

    local startAddress = 0x12340000
    local bytesToRead = 20
    local result = readBytesToString(startAddress, bytesToRead)
    print(result)
  15. 23 minutes ago, MAARS said:

    This would be possible if @Enyby add the Coroutine library that permit to run asynchronous code. I know some m***ed gg that people have implemented that lib you can dm me if you want to know more

    Can you explain how would coroutines make that possible? How would you pass execution to a coroutine after calling "searchNumber", when it is doing it's job? Coroutines don't make it possible to execute code in parallel.

  16. 21 minutes ago, MAARS said:

    Nope

    "Aarch64 = arm64" statement is correct. AArch64 is the name of 64-bit ARM architecture. Both names refer to the same thing.

  17. 8 hours ago, ctbear said:

    1. Add an API for converting byte array to string, such as

    gg.bytesToString({0,104,0,105}, "utf-16");

    , returns the string "Hi", similar to Java:

    return new String ({0,104,0,105}, "utf-16"); 

    To add to discussion of this suggestion:

    Lua strings by themselves are encoding-agnostic, so desired conversion is actually from bytes that represent string in one encoding to bytes that represent the same string in other encoding (utf-8 in this case, it seems). Input and output bytes of a hypothetical API function for such conversion can be in the form of strings or tables with values of bytes, but strings seem to be more reasonable option, because internally they are represented as array of bytes (as opposed to table with 8-byte integers).

    It's also worth to mention that GG API already has bytes function that converts bytes from utf-8 encoding to specified one, so it may be not a bad idea to extend the function by adding new parameter for source encoding (how to interpret string that is passed to the function) instead of creating a new function.

    As for what can be done currently, without such function:

    Since there is "utf8" library with functionality to construct a string from list of character codepoints, to be able to convert bytes from, for example, UTF-16LE encoding to UTF-8, it is enough to implement parsing of bytes that represent string in UTF-16LE encoding to list of character codepoints. The list then just need to be passed to "utf8.char" function and it will return desired string in UTF-8 encoding.

  18. 2 hours ago, XxhentaixX said:

    But its odd. So this means that when all the values of the elements are setted equal to the value of the first element it keeps a record of that current value saved, even if the value in the game has changed.

    This understanding is based on fundamental misconception that GG automatically updates anything in tables that have been returned with "getResults", "getValues" or other GG API functions. GG not only doesn't do that, but also wouldn't be able to do that without significant performance impact (just imagine having to read values from process memory for all elements of all tables that have been returned by GG API functions every N milliseconds).

    So changes in process memory "automatically" don't affect anything in script anyhow. To get updated data from process memory, corresponding GG API function ("getValues") needs to be called, but even it doesn't change anything in table that is passed to it as argument, instead it returns new table that has new values in "value" field of it's sub-tables.

  19. There is one other detail regarding the comparison to "0" (string).

    Behavior of comparison operators for this case is described in the manual as follows: 

    Quote

    Equality (==) first compares the type of its operands. If the types are different, then the result is false. Otherwise, the values of the operands are compared. Strings are compared in the obvious way. Numbers are equal if they denote the same mathematical value.

    Equality comparisons do not convert strings to numbers or vice versa. Thus, "0"==0 evaluates to false, and t[0] and t["0"] denote different entries in a table.

    The operator ~= is exactly the negation of equality (==).

    For our case it means that the following condition

    _x[i].value ~= '0'

    will always evaluate to "true", because "value" field has value of number type.

    Correspondingly, correct comparison to check for value being not equal to zero is: 

    _x[i].value ~= 0
  20. 3 minutes ago, TisNquyen said:
    gg.searchNumber('', gg.TYPE_FLOAT)
    gg.refineNumber('', gg.TYPE_FLOAT)
    local count = gg.getResultsCount()
    local results = gg.getResults(count)
    
    local _x, _y = {}, {}
    for i, v in ipairs(results) do
      _x[i] = {address = v.address + 0x44, flags = gg.TYPE_FLOAT}
      _y[i] = {address = v.address + 0x4C, flags = gg.TYPE_FLOAT}
    end
    _x, _y = gg.getValues(_x), gg.getValues(_y)
    
    local x, y = {}, {}
    for i, v in ipairs(results) do
      if _x[i].value ~= '0' then
        table.insert(x, x[i])
      end
      if _y[i].value ~= '0' then
       table.insert(y, y[i])
      end
    end
    
    if #x ~= #y then
      return print "the results from x and y may not be the same!"
    end
    local xValue, yValue = x, y
    
    for loop = 1, #x do
      for i, v in ipairs(x) do
        x[i].value = xValue[loop].value
        y[i].value = yValue[loop].value
      end
      gg.setValues(x)
      gg.setValues(y)
      gg.sleep(500)
    end

     

    This code is equivalent to your previous version.

    You don't make a copy of tables with this line: 

    local xValue, yValue = x, y

    Instead you create new variables that refer to the same tables, so it doesn't make any difference.

    Lua reference manual explains this pretty clearly: 

    Quote

    Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.

  21. 28 minutes ago, XxhentaixX said:

    So x[i].value stays is equal to the element 1 as long it is in the "for loop"  ?

    No, that's because all values of the table are explicitly set to value of first element when the following code is executed: 

    for i = 1, #x do
      x[i].value = x[1].value
    end

    If, for example, "x" has 3 elements, the loop is then equivalent to: 

    x[1].value = x[1].value -- value of first element is set to itself
    x[2].value = x[1].value -- value of second element is set to value of first element
    x[3].value = x[1].value -- value of third element is set to value of first element

    And then, when next loop is executed: 

    for i = 1, #x do
      x[i].value = x[2].value
    end

    "x[2].value" no longer has it's original value, because new value (of "x[1].value") has been assigned to it during execution of previous loop.

    This is why only first loop works as intended and all subsequent ones don't. And this is why copy of values needs to be created before the first loop (to have access to original values after table values have been overwritten).

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