Бывают случаи, когда авторы создают полезные плагины, но не делятся исходным кодом. Мне например не хочется использовать чужие плагины в своем моде, спрашивать разрешение авторов включать их в свою сборку, поэтому стараюсь все писать сам. Но как раздобыть необходимый адрес, если код закрыт. Если с CLEO-скриптами все просто, их можно открыть и посмотреть, вытащить оттуда все полезное, то с ASI-плагинами поможет только IDA PRO.
Многие знают плагин Img Limit Adjuster, но как он работает.
Сначала пойдем честным путем (я так и сделал). Подключение img-архива происходит в default.dat или gta_vc.dat командой CDIMAGE, отсюда легко это найти в IDA
На рисунке видно, что лимит img-архивов задается не ограничением количества CDIMAGE_COUNT, а размером памяти, выделенной под их названия CDIMAGE_NAMES и соответственно под сам массив указателей CDIMAGES. Получаем максимум 8 архивов, кроме gta3.img, больше просто некуда записать.
Теперь легко догадаться, что нам нужно просто увеличить область памяти для хранения указателей на архивы и их названий. Естественно эта область будет уже в другом месте, мы должны выделить ее сами. Первая область выделяется под названия, вторая под указатели.
void *CDIMAGE_NAMES; CDIMAGE_NAMES = VirtualAlloc(NULL,0x4000,MEM_COMMIT,PAGE_READWRITE);
void *CDIMAGES; CDIMAGES = VirtualAlloc(NULL,0x1000,MEM_COMMIT,PAGE_READWRITE);
Осталось перенаправить все первоначальные ссылки (их легко увидеть, нажав X в IDA), которые были на 0x6F7488 CDIMAGE_NAMES и 0x6F76D0 CDIMAGES на новые области
WriteDWORD((DWORD*)0x4081D2,(DWORD)CDIMAGE_NAMES);
WriteDWORD((DWORD*)0x40823A,(DWORD)CDIMAGE_NAMES);
WriteDWORD((DWORD*)0x408801,(DWORD)CDIMAGE_NAMES);
WriteDWORD((DWORD*)0x40818B,(DWORD)CDIMAGES);
WriteDWORD((DWORD*)0x408199,(DWORD)CDIMAGES);
WriteDWORD((DWORD*)0x4081C7,(DWORD)CDIMAGES);
WriteDWORD((DWORD*)0x408215,(DWORD)CDIMAGES);
WriteDWORD((DWORD*)0x408221,(DWORD)CDIMAGES);
WriteDWORD((DWORD*)0x40851B,(DWORD)CDIMAGES);
WriteDWORD((DWORD*)0x4086E1,(DWORD)CDIMAGES);
WriteDWORD((DWORD*)0x4087E2,(DWORD)CDIMAGES);
WriteDWORD((DWORD*)0x4087EE,(DWORD)CDIMAGES);
WriteDWORD((DWORD*)0x40885B,(DWORD)CDIMAGES);
WriteDWORD((DWORD*)0x408869,(DWORD)CDIMAGES);
На всякий случай моя процедура WriteDWORD, которая просто пишет в адрес 4 байта
void WriteDWORD(DWORD *Address, DWORD Value)
{
DWORD OldProtect; VirtualProtect(Address,sizeof(DWORD),PAGE_READWRITE,&OldProtect);
*Address = Value; VirtualProtect(Address,sizeof(DWORD),OldProtect,&OldProtect);
}
Теперь лимит img-архивов ограничивается только выделенной под них областью памяти.
Теперь о реверсе существующего плагина IMG Limit Adjuster. Я использовал это, только чтобы проверить свои описанные выше догадки, но те кто не догадаются, смогут с чего-то начать. Можно открыть плагин в IDA, сразу появится основная функция и действительно в ней видно, что автор руководствовался точно такой же логикой, два раза выделяется память VirtualAlloc и дальше перебрасываются на нее все ссылки через VirtualProtect. Это и означает, что адрес, переданный в качестве параметра в VirtualProtect будет меняться, их и смотрим.
Кстати, достаточно выделить память один раз и правильно распределить, по 64 байта под названия, по 4 под указатели.
P.S. А еще лучше обойтись динамическими массивами.