DoranekoSystems / frida-ceserver

Frida-based ceserver: A fusion of Cheat Engine and Frida.
GNU General Public License v3.0
222 stars 58 forks source link

Doesn't work on my device #1

Closed 6ag closed 2 years ago

6ag commented 2 years ago

Doesn't work on my device, the Python version I'm using is 3.8.2 and the Frida version is 14.2.14.

Can you tell me which version of Python and Frida you are using?

Thank you, brother.

DoranekoSystems commented 2 years ago

There was a bug in the api that prevented the memory search from working properly. I am using python-3.6.8 frida-15.1.14.

Do you have ceversion set properly in config.json? I would appreciate it if you could let me know what kind of problem you are experiencing.

6ag commented 2 years ago

Mobile device: iPhone X OS version: 14.0 Frida version: 15.1.12 Python version: 3.8.2

When I click Frist Scan in Cheat Engine 7.3, the app will crash after a while and the following error will appear:

Traceback (most recent call last):
  File "/Users/feng/DevEnv/frida-ceserver-main/ceserver.py", line 476, in main_thread
    ret = handler(conn, command, thread_count)
  File "/Users/feng/DevEnv/frida-ceserver-main/ceserver.py", line 296, in handler
    ret = API.ReadProcessMemory(address, size)
  File "/Users/feng/.pyenv/versions/3.8.2/lib/python3.8/site-packages/frida/core.py", line 468, in method
    return script._rpc_request('call', js_name, args, **kwargs)
  File "/Users/feng/.pyenv/versions/3.8.2/lib/python3.8/site-packages/frida/core.py", line 26, in wrapper
    return f(*args, **kwargs)
  File "/Users/feng/.pyenv/versions/3.8.2/lib/python3.8/site-packages/frida/core.py", line 400, in _rpc_request
    raise result[2]
frida.InvalidOperationError: script has been destroyed
6ag commented 2 years ago

config.json:

{
  "target": "",
  "targetOS": 2,
  "mode": 0,
  "arch": 2,
  "fix_module_size": false,
  "ceversion": "7.3",
  "manualParser": false,
  "javaDissect": false
}
6ag commented 2 years ago

I reinstalled python-3.6.8 frida-15.1.14 and still got the same error:

Traceback (most recent call last):
  File "/Users/feng/DevEnv/frida-ceserver-main/ceserver.py", line 476, in main_thread
    ret = handler(conn, command, thread_count)
  File "/Users/feng/DevEnv/frida-ceserver-main/ceserver.py", line 296, in handler
    ret = API.ReadProcessMemory(address, size)
  File "/Users/feng/.pyenv/versions/3.6.8/lib/python3.6/site-packages/frida/core.py", line 468, in method
    return script._rpc_request('call', js_name, args, **kwargs)
  File "/Users/feng/.pyenv/versions/3.6.8/lib/python3.6/site-packages/frida/core.py", line 26, in wrapper
    return f(*args, **kwargs)
  File "/Users/feng/.pyenv/versions/3.6.8/lib/python3.6/site-packages/frida/core.py", line 400, in _rpc_request
    raise result[2]
frida.InvalidOperationError: script has been destroyed

When I use the memory search function, the APP will crash after searching for about 1 minute.

DoranekoSystems commented 2 years ago

Is the frida-server on your iPhone device and the frida on your PC both up-to-date? Did it work with the previous version I distributed? I'm sorry for all the questions.

6ag commented 2 years ago

The previous version worked fine for me, and at the time I remember there was no config.json file.

I now iPhone frida-server and PC frida are the latest version, Python also reinstalled 3.6.

6ag commented 2 years ago

I just found an older version that I downloaded from GitHub last July and found that it still works fine. I am using python-3.8.2 frida-15.1.14.

DoranekoSystems commented 2 years ago

Thank you very much for your report. I will compare with the past ver and try to find the cause.

6ag commented 2 years ago

Unfortunately, I tested and found that older versions still occasionally flicker when searching memory.

I sincerely hope to fix this issue, thank you.

6ag commented 2 years ago

Sorry to interrupt again, but after testing I have made a new discovery. When Frida launches the APP using spawn mode, the APP has run successfully, but the script has some errors:

Traceback (most recent call last):
  File "/Users/feng/DevEnv/frida-ceserver-main/main.py", line 107, in <module>
    main(target)
  File "/Users/feng/DevEnv/frida-ceserver-main/main.py", line 50, in main
    process_id = device.spawn([app_identifier])
  File "/Users/feng/.pyenv/versions/3.8.2/lib/python3.8/site-packages/frida/core.py", line 26, in wrapper
    return f(*args, **kwargs)
  File "/Users/feng/.pyenv/versions/3.8.2/lib/python3.8/site-packages/frida/core.py", line 149, in spawn
    return self._impl.spawn(program, argv, envp, env, cwd, stdio, aux_options)
frida.TimedOutError: unexpectedly timed out while waiting for app to launch

When launched using attach mode, everything seems to work fine. The memory search also works fine and there is no app flashing. However, when I do a pointer scan, an error message appears: Failure copying target process memory.

What should I do to use the pointer scan function properly?

6ag commented 2 years ago

I found the reason for the app flashing. When searching memory or scanning the pointer, the memory occupied by the app keeps increasing, and it flashes when it exceeds the memory limit.

EXC_RESOURCE -> Bird[14899] exceeded mem limit: ActiveHard 1850 MB (fatal)

However, I don't know how to avoid the continuous growth of memory usage, which I guess is caused by Frida. Brother, can you solve this problem?

6ag commented 2 years ago

Executing Memory.readByteArray() function in a large amount will cause the memory occupied by the target APP to keep increasing and will not be released automatically, which will eventually lead to the target APP being killed by the system.

DoranekoSystems commented 2 years ago

Thank you for all the information. If possible, I will try to implement memory loading on my own in iOS.

6ag commented 2 years ago

Thank you brother, I hope this tool will become more and more perfect.

DoranekoSystems commented 2 years ago
readprocessmemory: function (address, size) {
    try {
      if (ptr(address).isNull() == false) {
        var ret = Memory.readByteArray(ptr(address), size);
        return false;
      } else {
        return false;
      }
    } catch (e) {
      return false;
    }
  },

What happens to the memory usage if I only read the memory and do not return? This may be a rpc problem.

6ag commented 2 years ago

I tested again and again for a day and found that it was indeed the call to the Memory.readByteArray function that caused the memory leak. If you don't execute Memory.readByteArray and return ByteArray directly, APP memory is not increased.

My guess is that there is a memory leak inside the Memory.readByteArray function.

6ag commented 2 years ago

Within the handler function CECMD.CMD_READPROCESSMEMORY branch of ceserver.py, I tried not executing the ReadProcessMemory function and there is no change in APP memory usage.

elif (command == CECMD.CMD_READPROCESSMEMORY):
    handle = reader.ReadUInt32()
    address = reader.ReadUInt64()
    size = reader.ReadUInt32()
    compress = reader.ReadInt8()
    # ret = API.ReadProcessMemory(address, size)
    # if (compress == 0):
    #     if ret != False:
    #         writer.WriteInt32(len(ret))
    #         ns.sendall(ret)
    #     else:
    #         writer.WriteInt32(0)
    # else:
    #     if ret != False:
    #         compress_data = zlib.compress(ret, level=compress)
    #         writer.WriteInt32(len(ret))
    #         writer.WriteInt32(len(compress_data))
    #         ns.sendall(compress_data)
    #     else:
    #         writer.WriteInt32(0)
    #         writer.WriteInt32(0)
    writer.WriteInt32(0)

And by executing the ReadProcessMemory function, the memory will skyrocket.

    elif (command == CECMD.CMD_READPROCESSMEMORY):
    handle = reader.ReadUInt32()
    address = reader.ReadUInt64()
    size = reader.ReadUInt32()
    compress = reader.ReadInt8()
    ret = API.ReadProcessMemory(address, size)
    # if (compress == 0):
    #     if ret != False:
    #         writer.WriteInt32(len(ret))
    #         ns.sendall(ret)
    #     else:
    #         writer.WriteInt32(0)
    # else:
    #     if ret != False:
    #         compress_data = zlib.compress(ret, level=compress)
    #         writer.WriteInt32(len(ret))
    #         writer.WriteInt32(len(compress_data))
    #         ns.sendall(compress_data)
    #     else:
    #         writer.WriteInt32(0)
    #         writer.WriteInt32(0)
    writer.WriteInt32(0)

Get the memory occupied by.

+ (double)usedMemory
{
    task_basic_info_data_t taskInfo;
    mach_msg_type_number_t infoCount = TASK_BASIC_INFO_COUNT;
    kern_return_t kernReturn = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&taskInfo, &infoCount);
    if (kernReturn != KERN_SUCCESS) {
        return NSNotFound;
    }
    return taskInfo.resident_size / 1024.0 / 1024.0;
}

Get the remaining free memory of the app.

+ (double)availableMemory
{
    if (@available(iOS 13.0, *)) {
        return os_proc_available_memory() / 1024.0 / 1024.0;
    }

    vm_statistics_data_t vmStats;
    mach_msg_type_number_t infoCount = HOST_VM_INFO_COUNT;
    kern_return_t kernReturn = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmStats, &infoCount);
    if (kernReturn != KERN_SUCCESS) {
        return NSNotFound;
    }
    return (vm_page_size *vmStats.free_count) / 1024.0 / 1024.0;
}

Before I started testing, usedMemory was getting a memory footprint of about 600M and availableMemory was getting about 1000M of free memory.

Cheat Engine starts scanning memory, specifying the search range 0x105000000 - 0x110000000. The memory footprint obtained by usedMemory continues to increase to 1300M, and the available memory obtained by availableMemory slowly decreases to 800M.

Then test the scan pointer and set the base address range to 0x105000000 - 0x110000000. The memory usage obtained by usedMemory continues to increase to about 1500M, and then slowly decreases to about 700M. The available memory fetched by availableMemory slowly decreases to 200M.

At this time I have to scan the memory again, or scan the pointer, and the app will definitely be killed by the system.

DoranekoSystems commented 2 years ago

Thank you for the information. If the solution seems to be too difficult, I would consider using the native ceserver only for the memory loading process.

Cheat Engine <-> python <-> native ceserver(ios)

6ag commented 2 years ago

Thank you brother. Looking forward to your update.

DoranekoSystems commented 2 years ago

I implemented the above type of memory reading from the outside. https://www.youtube.com/watch?v=KkKDSTcecwg

6ag commented 2 years ago

Thank you very much, I have tested it and it's perfect. The performance is great 👍🏻.

DoranekoSystems commented 1 year ago

If possible, it would be helpful if you could make sure it is fixed in the latest commit.