[Game][Unity] Memory Tips

koo00·2024년 1월 17일

I. Intro

유니티 게임에서 메모리에 접근할 때 팁
유니티로 한정지었지만 다른 앱에서도 비슷하게 접근하면 되지 않을까 하는 생각을 하며 시작.


II. List

  • List.size = List.add(0x18)
    List.base = List.add(0x10).readPointer()
    List[0] = base.add(0x20)

  • List<T>의 다음 인덱스 값의 위치는 T의 필드 크기에 따라 달라지는 듯
    List<int> → 4
    List<Object> → Object의 필드 크기

Example 1)

List<int\> m_list;	// m_list의 인덱스 크기는 4 (int)
int id;

size = m_list.add(0x18) = 2 라면
base = m_list.add(0x10).readPointer()

first_index = base.add(0x20);
second_index = base.add(0x24);

for 문으로 정리하면

for (var i=0; i<size; i++) {
	var id = base.add(0x4 * i).add(0x20);
    console.log('[+] id : ' + id);
}

Example 2)

List<Item\> m_list;	// m_list의 인덱스 크기는 0x10 (int + int + int + int)
class Item {
	int Type, int Id, int Value, int Tm;
}

size = m_list.add(0x18) = 4 라면
base = m_list.add(0x10).readPointer() = 첫번째 Item

m_list[0].Type = m_list.add(0x10).readPointer().add(0x20);
m_list[0].Id = m_list.add(0x10).readPointer().add(0x24);
m_list[0].Value = m_list.add(0x10).readPointer().add(0x28);
m_list[0].Tm = m_list.add(0x10).readPointer().add(0x2C);

m_list[1].Type = m_list.add(0x10).readPointer().add(0x10).add(0x20);
m_list[1].Id = m_list.add(0x10).readPointer().add(0x10).add(0x24);
m_list[1].Value = m_list.add(0x10).readPointer().add(0x10).add(0x28);
m_list[1].Tm = m_list.add(0x10).readPointer().add(0x10).add(0x2C);

...


III. Array

배열은 일단 정확하진 않음 → 값은 0x20 부터 존재함

Example 3)

S_Object[] m_obj;	// m_obj의 인덱스 크기는 8 (int + int)
class S_Object {
	int Id, int Value;
}

m_obj.size = m_obj.add(0x18) = 3 이라면

m_obj[0]= m_obj.add(0x20);
m_obj[0].Id= m_obj.add(0x20);
m_obj[0].Value = m_obj.add(0x24);

m_obj[1] = m_obj.add(0x8).add(0x20);
m_obj[1].Id = m_obj.add(0x8).add(0x20);
m_obj[1].Value = m_obj.add(0x8).add(0x24);

m_obj[2] = m_obj.add(0x10).add(0x20);
m_obj[2].Id = m_obj.add(0x10).add(0x20);
m_obj[2].Value = m_obj.add(0x10).add(0x24);


IV. Property

필드 접근은 offset 이 바로 보여서 쉬운데 프로퍼티에는 어떻게 접근하냐?
→ 프로퍼티는 IDA 에서 함수 형태로 나와있어서 class$$get_propertyIDA 로 확인해보면 class + offset 을 리턴하는 것을 볼 수 있고, 나중에 해당 offset 으로 접근하면 된다.

Example)

class Obj
{
	...
    public int id
    {
        get
        {
            return 0;
        }
        set
        {
        }
    }
}
Obj obj;

Obj$$get_idIDA로 확인해보면 return Obj + offset; 확인 가능
따라서 id = obj.add(offset);


IV. Dictionary

여기는 25.11.18 에 추가. 엔트리에 key 와 value 가 존재한다.
26.06.09 내용 추가

struct Entry {
    int hashCode; // 4
    int next;     // 4
    TKey key;     // sizeof(TKey)
    TValue value; // sizeof(TValue)
}

public Dictionary<eType, float> TestDict;					// enum eType = int

base = TestDict;
size = base.add(0x20).readInt();
entries = base.add(0x18).readPointer();
entriesData = entries.add(0x20);

entries[0].hashCode = entriesData.add(0x10 * 0).add(0x0);	// int
entries[0].next = entriesData.add(0x10 * 0).add(0x4);		// int
entries[0].key = entriesData.add(0x10 * 0).add(0x8);		// int
entries[0].value = entriesData.add(0x10 * 0).add(0xC);		// float

entries[1].hashCode = entriesData.add(0x10 * 1).add(0x0);	// int
entries[1].next = entriesData.add(0x10 * 1).add(0x4);		// int
entries[1].key = entriesData.add(0x10 * 1).add(0x8);		// int
entries[1].value = entriesData.add(0x10 * 1).add(0xC);		// float
...


public Dictionary<eType, Object> TestDict2;

base = TestDict2;
...
entries = base.add(0x18).readPointer();
entriesData = entries.add(0x20);

entries[0].hashCode = entriesData.add(0x18 * 0).add(0x0);	// int
entries[0].next = entriesData.add(0x18 * 0).add(0x4);		// int
entries[0].key = entriesData.add(0x18 * 0).add(0x8);		// int
entries[0].value = entriesData.add(0x18 * 0).add(0x10);		// pointer
...
const dict = args[3]; // Dictionary<int, long>

const count = dict.add(0x20).readS32();
const entries = dict.add(0x18).readPointer();

console.log("[Dict<int,long>] count =", count);
console.log("[Dict<int,long>] entries =", entries);

if (!entries.isNull()) {
    const entriesData = entries.add(0x20);

    for (let i = 0; i < count; i++) {
        const entry = entriesData.add(0x18 * i);

        const hashCode = entry.add(0x0).readS32();
        const next = entry.add(0x4).readS32();
        const key = entry.add(0x8).readS32();
        const value = entry.add(0x10).readS64();

        if (hashCode < 0) continue;

        console.log("---- entry[" + i + "] ----");
        console.log("hashCode =", hashCode);
        console.log("next     =", next);
        console.log("key      =", key);
        console.log("value    =", value.toString());
    }
}

V. Outro

12월에 업로드 해야지 생각했다가 깜빡하고 이제서야 올림..
암튼 나중에 유용하게 써먹을듯

profile
JFDI !

0개의 댓글