유니티 게임에서 메모리에 접근할 때 팁
유니티로 한정지었지만 다른 앱에서도 비슷하게 접근하면 되지 않을까 하는 생각을 하며 시작.
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() = 첫번째 Itemm_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);...
배열은 일단 정확하진 않음 → 값은 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);
필드 접근은 offset 이 바로 보여서 쉬운데 프로퍼티에는 어떻게 접근하냐?
→ 프로퍼티는 IDA 에서 함수 형태로 나와있어서 class$$get_property 를 IDA 로 확인해보면 class + offset 을 리턴하는 것을 볼 수 있고, 나중에 해당 offset 으로 접근하면 된다.
Example)
class Obj { ... public int id { get { return 0; } set { } } } Obj obj;
Obj$$get_id 를 IDA로 확인해보면 return Obj + offset; 확인 가능
따라서 id = obj.add(offset);
여기는 25.11.18 에 추가. 엔트리에 key 와 value 가 존재한다.
public Dictionary<eType, float> TestDict; // enum eType = int
base = TestDict;
size = base.add(0x20).readInt();
buckets = base.add(0x10); // buckets = int[]
bucketsData = buckets.add(0x20);
entries = base.add(0x18); // entries = Entry[]
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);
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
...
12월에 업로드 해야지 생각했다가 깜빡하고 이제서야 올림..
암튼 나중에 유용하게 써먹을듯