Перейти к содержанию
Решена проблема отправки писем ×
АнимеФорум

Вскрываем визуалки


dsp8195

Рекомендуемые сообщения

Насколько мне известно, до нас доходят либо версии, "адаптированные" для США, либо пиратские рипы (что, в принципе, одно и тоже). Разумеется, русского языка в них не наблюдается.

 

Потому я и работал над программой AnimED, чтобы стало возможным самостоятельно перевести тексты и графику в меню и задниках (это, собственно, и есть "аниме-моддинг в чистом виде". Сомневаюсь, что у нас кто-то захочет переозвучить или перерисовать персонажей, ибо это испортит стиль и атмосферу).

 

Вполне возможно, что кто-то уже сделал утилиты для вскрытия (у "Триады" они точно были, т.к. я встречал переведённую графику в их релизах).

 

Но, сделать нечто подобное самостоятельно, да ещё и получить бесценную экспу в кодинге...

 

Поэтому, кто сказал, что моддинг необходим только хитам вроде The Elder Scrolls IV? И "маленькие" игры заслуживают внимания (особенно если в них подчас заложено столько юмора и жизнерадостности, сколько нет ни в какой GTA).

 

Эта тема создана очень давно (первая тема и первое сообщение вашего покорного слуги на анимефорум.ру), но не использовалась по прямому назначению (поэтому не обращайте внимания на два последующих ответа - они более не имеют логической связи с содержимым темы).

 

Поскольку сейчас объём реверз-инженируемого кода более не органичивается одними только архивами визуалок, рекомендую вести дискуссию по вскрываемым форматам именно здесь. Тем более, что есть повод. ;)

Изменено пользователем WinKi-тян (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

  • 8 месяцев спустя...

Serke, несколько минут назад я получил исходники кода анпакера графики в формате GGP, который наповерку оказался шифрованным по ксор-ключу PNG.

 

//It's compressed, but not that difficult. Just a masked PNG.
//The structure as follows: (don't care about the member names!)

typedef unsigned long UInt32; // 32-bit unsigned integer
typedef unsigned short UInt16; // 16-bit unsigned integer

struct GGP {
char sig[8] = "GGPFAIKE"; // master string
UInt32 depth; // 0:use image's value / 32:ARGB / 24:RGB
char xor[8]; // sub string
UInt32 offset, length;
UInt32 regionOffset, regionLength;
char ggxRegion[regionLength];
char data[length];  // masked PNG image
};

struct GGxRegion {
UInt16 destLeft, destTop; // destination position
UInt16 left, top, width, height; // source bounds
};

//The data can be unmasked using xor-ing (GGP.sig xor GGP.xor) (confusing!)
//so an unoptimized code would be:

for(i = 0; i < length; i++)
	data[i] ^= sig[i % 8] ^ xor[i % 8];

//ggxRegion is used for overlay images of the message window and the like.

Ссылка на комментарий
Поделиться на другие сайты

  • 3 недели спустя...

Поскольку депресняк пока не думает отступать, а время идет, решил кинуть код анпакера GGD в таком виде, в каком он есть. Он полностью работоспособен, не хватает разве что комментариев и кода проверки GGD-файлов по идентификатору.

 

#include <stdio.h>
#include <windows.h>

int ExtractGGD( HANDLE hFile, BYTE *pDst, DWORD Size );
int BufferizedRead( HANDLE hFile, BYTE *lpBuf, DWORD NumOfBytesToRead, BOOL IsInit );

int main( int argc, char **argv)
{
struct t_GGDHeader {
	BYTE id[4];
	WORD width;
	WORD height;
} GGDHeader;

char szoutf[ MAX_PATH ];
HANDLE hFile, hOutf;
DWORD BytesRead, BytesWritten, DataLen;
BYTE *pGGDData;

printf( "IKURA GGD images extractor 0.01\n" );
printf( "Extraction code is a courtesy of IKURA;-)\n" );

if( argc > 1 )
{ 
	hFile = CreateFile( argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
						FILE_ATTRIBUTE_NORMAL, NULL );

	if( hFile != INVALID_HANDLE_VALUE )
	{
		ReadFile( hFile, &GGDHeader, sizeof( GGDHeader ), &BytesRead, NULL );
		DataLen = ( ( ( GGDHeader.width * 3 + 3 ) >> 2 ) << 2 ) * GGDHeader.height;
		pGGDData = (BYTE *)malloc( DataLen );
		ExtractGGD( hFile, pGGDData, DataLen );
		wsprintf( szoutf, "%s%s", argv[1], ".unpacked" );
		hOutf = CreateFile( szoutf, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
							FILE_ATTRIBUTE_NORMAL, NULL ); 
		WriteFile( hOutf, pGGDData, DataLen, &BytesWritten, NULL );
		free( pGGDData );
		CloseHandle( hOutf );
		CloseHandle( hFile );
	}
	else
		printf( "Cannot open file %s\n", argv[1] );
}
else
	printf( "Usage: unpack_ggd filename<.ggd>\n" );

return 0;
}

//////////////////////////////////////////////////////////////////////////////
// Глобальные переменные, используемые ф-ей BufferizedRead //

struct t_cyc_buf {
BYTE array1[0x800];
BYTE array2[0x800];
} cyc_buf;

DWORD DataBlockLen;
BYTE *pDataBlockCurrByte;
BOOL IsLastBlock;

int ExtractGGD( HANDLE hFile, BYTE *pDst, DWORD Size )
{
BYTE *pDstEnd, *pSrc;
BYTE ctrlb;
BYTE buf[8];
int i;  
 
BufferizedRead( NULL, NULL, 0, TRUE ); // инициализация глобальных переменных используемых ф-ей BufferizedRead()
pDstEnd = Size + pDst;
	
while( pDst < pDstEnd ) 
{
	if( BufferizedRead( hFile, &ctrlb, 1, FALSE ) == -1 )
		return 1;
	switch( ctrlb )
	{

		case 0:

			if( BufferizedRead( hFile, buf, 1, FALSE ) == -1 )
				return 1;

			buf[1] = *( pDst - 3 );
			buf[2] = *( pDst - 2 );
			buf[3] = *( pDst - 1 );

			for( i = 0; i < buf[0]; i++ )
			{
				*pDst++ = buf[1];
				*pDst++ = buf[2];
				*pDst++ = buf[3];
			}
			break;

		case 1:

			if( BufferizedRead( hFile, buf, 2, FALSE ) == -1 )
				return 1;
			pSrc = pDst - ( buf[1] * 3 );
			for( i = 0; i < buf[0] * 3; i++ )
				*pDst++ = *pSrc++;
			break;

		case 2:

			if( BufferizedRead( hFile, buf, 3, FALSE ) == -1 ) 
				return 1;
			pSrc = pDst - MAKEWORD( buf[1], buf[2] ) * 3;
			for( i = 0; i < buf[0] * 3; i++ )
				*pDst++ = *pSrc++;
			break;

		case 3:

			if( BufferizedRead( hFile, buf, 1, FALSE ) == -1 )
				return 1;
			pSrc = pDst - ( buf[0] * 3 );
			*pDst++ = *pSrc++;
			*pDst++ = *pSrc++;
			*pDst++ = *pSrc;
			break;

		case 4:

			if( BufferizedRead( hFile, buf, 2, FALSE ) == -1 )
				return 1;
			pSrc = pDst - MAKEWORD( buf[0], buf[1] ) * 3;
			*pDst++ = *pSrc++;
			*pDst++ = *pSrc++;
			*pDst++ = *pSrc;
			break;

		default:

			for( i = 0; i < ctrlb - 4; i++ )
			{
				if( BufferizedRead( hFile, buf, 3, FALSE ) == -1 )
					return 1;
				*pDst++ = buf[0];
				*pDst++ = buf[1];
				*pDst++ = buf[2];
			}
			break;
	}
}
return 1;
}

int BufferizedRead( HANDLE hFile, BYTE *lpBuf, DWORD NumOfBytesToRead, BOOL IsInit )
{
int i;
void *pTemp;
DWORD BytesRead;

if( IsInit )
{
	pDataBlockCurrByte = NULL;
	DataBlockLen = 0;
	IsLastBlock = FALSE;

	return 0;
}
if( pDataBlockCurrByte == NULL )
{
	ReadFile( hFile, cyc_buf.array1, 0x1000, &DataBlockLen, NULL );
	if( DataBlockLen < 0 )
		return -1;
	pDataBlockCurrByte = cyc_buf.array1;
	if( DataBlockLen < 0x1000 )
		IsLastBlock = TRUE;
} 
if( (DataBlockLen <= 0) || (DataBlockLen < NumOfBytesToRead) )
	return -1;
for( i = 0; i < NumOfBytesToRead; i++ )
{
	lpBuf[ i ] = *pDataBlockCurrByte++;
	DataBlockLen--;
	if( pDataBlockCurrByte > &cyc_buf.array2[0x7FF] )
		pDataBlockCurrByte = cyc_buf.array1;
}
if( (DataBlockLen >= 0x800) || IsLastBlock )
	return NumOfBytesToRead;

pTemp = cyc_buf.array1;

if( pDataBlockCurrByte < cyc_buf.array2 )
	pTemp = cyc_buf.array2;

ReadFile( hFile, pTemp, 0x800, &BytesRead, NULL ); 

if( BytesRead >= 0 )
{
	if( BytesRead < 0x800 )
		IsLastBlock = TRUE;

	DataBlockLen += BytesRead;
	return NumOfBytesToRead;
}

IsLastBlock = TRUE;
return NumOfBytesToRead;
}

 

Идентификатор id в GGDHeader это строка (НЕ оканчивающаяся нулем) зашифрованная по методу NOT (или XOR 0xFF, если так больше нравится). Может иметь значения 'FULL', 'HIGH', '256G' и возможно, какие-то еще.

 

Если будешь писать конвертер графики, выложу соответствующую информацию.

 

Функция буферизованого чтения (BufferizedRead) вытащена исключительно из любви к искусству. Тебе она, по большому гамбургскому счету, нафиг не нужна - проще прочитать один раз весь файл в память, а затем 'скармливать' его функции распаковки по кусочкам, как это делает анпакер GG2.

 

Вопросы сюда. >__<

 

EDIT: слегка подправил код.

Изменено пользователем Serke (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

Спасибо! -_-

 

Правда... теперь депресняк у меня... если сейчас прикоснусь к Дельфи, заброшу перевод.

 

FULL - видимо, 24-битные.

HIGH - 16-и.

256G - 256-цветные с палитрой.

Изменено пользователем WinKi-тян (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

  • 3 недели спустя...

WinKi, ты когда-нибудь с NScripter'ом работал? У меня проблема - экзешник из скачанного архива с последней версией NScripter'а отказывается работать с игрой на базе более старой версии движка, выдавая в качестве объяснения какой-то мунспик =). Собственно, меня интересует, нужно ли каким-то образом обрабатывать взятые "из коробки" экзешники движков онскриптера и энскриптера напильником для каждой конкретной игры.

 

P.S. NScripter "внутри" просто кошмарен. Код настолько уродлив, что им можно детей пугать...

Изменено пользователем Serke (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

nScripter устарел (и пользоваться им не стоит, даже переключив язык системы для не-Unicode программ на японский - код там действительно ужасен).

 

OnScripter - иной разговор. Доводить EXE до нужной кондиции, как правило, не требуется (только русский он, зараза, всё равно не держит - для этого был придуман POnScripter (скину ссылку на мой экземпляр исходников в личку - они, кхм, неофициальные) ).

 

Однако, об этом уже говорили на Gemot'е: существует так называемый "прародитель" - Scripter3 (или как там его). В общем, не совместим он с асм-подобным языком nScripter'а. ;);

Ссылка на комментарий
Поделиться на другие сайты

WinKi, наверное, мне нужно было объяснить мою задачу. Я ищу способ хакнуть движок NScripter'а так, чтобы он воспринимал однобайтовые символы и производил text wrapping, также пытаюсь заставить его работать с шрифтом, символы в котором переменной, не фиксированной ширины. Отсутствие поддержки русского языка меня волнует в последнюю очередь.

 

NScripter никак не может быть отсталым по сравнению с ONScripter'ом, потому что он есть модель для этого самого ONScripter'а - сначала нововведения появляются в NScripter'е, потом с большим опозданием они перекочевывают в ONScripter. Собственно говоря, причиной, по которой я вынужден ковырять NScripter является отсутствие поддержки многих функций, используемых игрой, текущей версией ONScripter'а.

 

[url="http://www.baka-tsuki.net/project/index.php?title=Talk:Umineko_no_Naku_Koro_ni" target="_blank" rel="nofollow">http://www.baka-tsuki.net/project/index.ph...no_Naku_Koro_ni[/url]

 

Поскольку Umineko no Naku Koro ni у меня пока нет, я сперва решил "потренироваться" на экзешнике Higurashi no Naku Koro ni, потом сообразил, что поскольку Umineko использует NScripter более новой версии, имеет смысл ковырять экзешник самой последней версии движка. Проблема в том, что экзешник последней версии почему-то отказывается работать с Higurashi, ругаясь на какое-то место в скрипте.

 

код там действительно ужасен

Я имел в виду бинарный код самого движка, не скриптовый язык =).

 

И еще такой вопрос... В коде движка есть обработка управляющего символа '#', который, как я понимаю, задает цвет текста. Код цвета задается в шестнадцатиричной форме сразу после этого символа (напр. так: #fffff). Движок преобразует этот код из символьной в бинарную форму, затем производит над полученным числом странные манипуляции. Например, такие (color_code - полученный из скрипта код цвета):

 

dword_5DC3F0 = color_code / 65536;

v89 = color_code & 0x8000FFFF;
if ( v89 < 0 )
v89 = ( ( v89 - 1 ) | 0xFFFF0000 ) + 1;

v90 = v89 / 256;
v91 = v89 & 0x800000FF;
dword_5DC3E8 = v90;

if ( v91 < 0 )
v91 = ( ( v91 - 1 ) | 0xFFFFFF00 ) + 1;
dword_5DC3E0 = v91;

v1 = some_array[ 256 * dword_5DC3F0 ];
v2 = some_array[ 256 * v90 ];
v3 = some_array[ 256 * v91 ];

 

Есть идея, что это может означать? =) Конкретно интересует, что из себя представляют глобальные переменные dword_XXXXXX и что из себя представляет массив some_array.

Ссылка на комментарий
Поделиться на другие сайты

Я ищу способ хакнуть движок NScripter'а так, чтобы он воспринимал однобайтовые символы и производил text wrapping, также пытаюсь заставить его работать с шрифтом, символы в котором переменной, не фиксированной ширины.

Документацию POnScripter'а прочитай... :);; Всё вышеперечисленное + смена TypeFace шрифта на лету!

Я имел в виду бинарный код самого движка, не скриптовый язык =).
...это и имелось ввиду. >_<
Есть идея, что это может означать? =) Конкретно интересует, что из себя представляют глобальные переменные dword_XXXXXX и что из себя представляет массив some_array.

 

dword_5DC3F0 = color_code / 65536;
//Тоже самое, что (R+G+B) div 3. Получается пиксель в оттенках серого.

v89 = color_code & 0x8000FFFF;
// Убивает каналы A и R (присваивает им нули), а в v89 получается G и B. Код, мягко говоря, извращённый.

if ( v89 < 0 )
// меньше нуля? хм... всё верно - цвет может записываться и как отрицательное число (TColor в Delphi)
v89 = ( ( v89 - 1 ) | 0xFFFF0000 ) + 1; // вот это я вообще не понял... негатив A R ... только в чём смысл? O_o

v90 = v89 / 256; // Ну, тут ясно -- получение оттенка серого из G и B
v91 = v89 & 0x800000FF; // получается серый пиксель (т.е. канал B, просто отделённый от изображения)
dword_5DC3E8 = v90; // это даже комментировать не стоит

if ( v91 < 0 )
//и это
v91 = ( ( v91 - 1 ) | 0xFFFFFF00 ) + 1; // по идее, получается 0
dword_5DC3E0 = v91;

v1 = some_array[ 256 * dword_5DC3F0 ];
v2 = some_array[ 256 * v90 ];
v3 = some_array[ 256 * v91 ];

// Кхм.... такого дикого и абсолютно бесполезного преобразования цветов я ещё не видел... если честно, не могу вкурить, зачем ЭТО нужно... :-P

Проблема в том, что экзешник последней версии почему-то отказывается работать с Higurashi, ругаясь на какое-то место в скрипте.
Не повезло. Эта игра использует модифицированную версию движка (просто моё предположение, но скорее всего так оно и есть). Изменено пользователем WinKi-тян (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

WinKi, ты надо мной издеваешься что-ли? :) . Я не сомневаюсь в том, что опенсорсный ONScripter и его ветки поддерживают весь набор трутайп шрифтов, юникод и прочее. Проблема в том, что он не поддерживает ряд графических эффектов последних версий NScripter'а, а значит перевести на него игры, использующие этот набор (вроде вышеупомянутой Umineko...) нельзя. Неужели ты думаешь, что я от нечего делать ковыряюсь в этой помойке? ;)

 

...это и имелось ввиду. >_<

Т.е. ты тоже дизасмил экзешник NScripter'а? :D

 

За комментарии к листингу - большое спасибо :) .

Изменено пользователем Serke (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

он не поддерживает ряд графических эффектов последних версий NScripter'а, а значит перевести на него игры, использующие этот набор (вроде вышеупомянутой Umineko...) нельзя.
Нельзя так нельзя. Надо было сказать сразу. :) Изменено пользователем WinKi-тян (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

Нет графических эффектов? Каких интересно? Чего-то вроде "oldmovie" или "sunblick"?

Не знаю. Игры у меня пока нет.

 

Если их отстутствие не испортит игру, то закомментировать проблемные участки скрипта и вперёд!

"Это не наш метод" ©. Можно вообще дать страждущим скрипт (в виде текстового файла), выдранный набор картинок и указания, где какой mp3 файл включать в винампе =). Ключевое слово здесь - экспириенс и он должен быть если не аутентичным, то хотя бы максимально приближаться к таковому. Мои пять центов.

 

А если нужны как воздух - обращаться прямо к Peter'у. Мы с Mion'ом добавили поддержку locale.utf, может и тебе повезёт.

Сомневаюсь. Затраты времени на поддержку локали и эмуляцию (или, скорее, симуляцию) граф. эффектов несравнимы.

 

или сделать копи-паст декомпилированного кода

Копи-паст сделать не получится, но идея мне нравится. Попробую.

 

Кстати, в ONScripter'е мне категорически не нравится то, что он использует для проигрывания OGG и MP3 библиотеку sdl_mixer. Не радует ни качество звука, ни лаги в проигрывании пожатого аудио, выражающиеся в появлении щелчков и потрескиваний.

Ссылка на комментарий
Поделиться на другие сайты

Кстати, в ONScripter'е мне категорически не нравится то, что он использует для проигрывания OGG и MP3 библиотеку sdl_mixer. Не радует ни качество звука, ни лаги в проигрывании пожатого аудио, выражающиеся в появлении щелчков и потрескиваний.

Вот и повод опробовать BASS. ;)

Ссылка на комментарий
Поделиться на другие сайты

Какая жалость, что OllyDbg не поддерживает удаленную отладку через TCP/IP - фичу, при ковырянии новелл и вообще любых графических аппликаций, совершенно незаменимую. Отладчик IDA Pro ее поддерживает, но он a) тормозной и б) неудобный (ИМХО) и наконец, в) в "японифицированных" виндах не отображаются регистры. ;)

 

WinKi, ты на уровне WinAPI, или вернее, GDI32 API, с графикой работал?

Изменено пользователем Serke (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

WinKi, ты на уровне WinAPI, или вернее, GDI32 API, с графикой работал?

Нет пока... -_- Насчёт регистров... шрифт в самом отладчике поменять пытался? Или (изврат конечно, и вряд ли бы сработало, но) запускать отладчик на японизированной винде через AppLocale?

Изменено пользователем WinKi-тян (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

Я крупно стормозил. Настолько крупно, что даже неудобно в этом признаваться. Японский для неюникодных приложений должен быть установлен на машине-сервере, на которой выполняется программа. На машине-клиенте же (т.е. на компьютере, с которого и происходит весь процесс управления отладкой) может быть установлен хоть суахили.

 

Еще возникло несколько вопросов. Во-первых, ф-ей setwindow задается в том числе и размер шрифта. Вопрос: в каких единицах он задается? В коде NScripter'а есть такой участок:

 

  if ( WriteVertical == TRUE )
 {
//...
 }
 else
 {
font_cx = 3 * font_width / 2;
font_cy = 3 * font_height;
 }
 hFont = CreateFontA( font_cy, font_cx, cOrientation, cOrientation, v19, 0, 0, 0, SHIFTJIS_CHARSET, 0, 0, 0, 1, &pszFaceName );

 

font_cy и font_cx - размеры шрифта в логических единицах (logical units).

font_width и font_height - параметры, переданные команде setwindow.

Как видно из вышеприведенного листинга, реальный размер шрифта отличается от заданного ф-ей setwindow.

 

Есть подозрение, что выводимые на экран символы шрифта размера width = font_cx, height = font_cy рендерятся движком в квадратную битмапку размерностью width = font_width, height = font_height (посимвольно), затем каждый символ копируется на экран API-функцией BitBlt (растровая операция SRCCOPY). Ты не мог бы взглянуть в исходники ONScripter'а и подтвердить/опровергнуть это?

 

И еще один вопрос: что представляет из себя поставляемый с бинарниками онскриптера шрифт default.ttf? Он вообще фиксированной или переменной ширины? =)

 

UPD: Можешь объяснить принцип работы ф-и locate? (той, которая "changes the position of characters without changing the position of the text window") Она только на строку, следующую непосредственно за ней оказывает эффект или вообще на весь выводимый текст?

 

Вообще, хотелось бы заиметь хоть какой-нибудь мануал по командам/функциям ONScripter'а. Смог найти только перечень с кратким описанием на сайте Haeleth. Кстати, и этот перечень неплохо было бы иметь в виде CHM-файла или хотя бы HTMLок...

Изменено пользователем Serke (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

товарищи!! я это хотеть!!!!!

знаю ассемблер, есть опыт вскрытия коммерческих продуктов на предмет регистрации.

вскрывал при помощи оллидебагера и softice'а

люблю хигурашу.

просто скажите что откуда качать и что нужно выдрать из этого скаченного, я с радостью попытаюсь это сделать

Ссылка на комментарий
Поделиться на другие сайты

Тут, в общем, опыт вскрытия ПО мало пригодится, нужны опыт реверсинга, опыт работы с IDA Pro (как дизассемблером, так и отладчиком) и знание GDI32 API...

 

Речь, кстати, идет не о хигураши, а о новой игре от создателей Higurashi (студии 07 Expansion) - Umineko no Naku Koro ni. Игры у меня на данный момент нет, пока она идет ко мне по почте, я набиваю руку, ковыряя Higurashi no Naku Koro ni (она на базе того же движка, что и Umineko..., только более старой версии). Higurashi..., иначе как в обучающих целях, ковырять нет смысла, так как ее скрипт совместим с последними версиями ONScripter'а - опенсорсного аналога популярного движка NScripter, на котором бегают все игры от 07 Expansion (и куча других игр). А вот скрипт Umineko... содержит ряд команд, отсутствующих в ONScripter'е, поэтому выхода два: "учить" NScripter работать с английским текстом или "научить" ONScripter этим новым командам. Мне ближе первый вариант :)

Изменено пользователем Serke (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

И еще один вопрос: что представляет из себя поставляемый с бинарниками онскриптера шрифт default.ttf? Он вообще фиксированной или переменной ширины? =)

Фиксированной. И в этом главный бич nScripter'а и OnScripter'а (поэтому я и дал исходники POnScripter'а).

 

Вообще, хотелось бы заиметь хоть какой-нибудь мануал по командам/функциям ONScripter'а. Смог найти только перечень с кратким описанием на сайте Haeleth. Кстати, и этот перечень неплохо было бы иметь в виде CHM-файла или хотя бы HTMLок...

 

Держи:

Ссылка на комментарий
Поделиться на другие сайты

Фиксированной. И в этом главный бич nScripter'а и OnScripter'а (поэтому я и дал исходники POnScripter'а).

Этот "главный бич" сильно упрощает задачу...

 

Пришел к неутешительному для себя выводу, что для того, чтобы полноценно хакнуть этот ужас, потребуется как минимум месяц работы. И это только для того, чтобы заставить движок понимать ASCII-строки. Код парсинга строк в NScripter'е размазан тоненьким слоем по всему движку.

 

В общем, этим путем я решил не идти. =) Английский текст, как и японский, будет в Shift-JIS, врезать в движок код, осуществляющий преобразование символов из Shift-JIS в ASCII перед выводом их на экран, думаю, будет несложно. Есть и другая, совершенно фантастическая по степени извращенности идея - врезать в код движка свой парсер. Английский текст будет, как ему и полагается, в ASCII, при загрузке скрипта, после его декодирования, управление получит мой парсер, который строку за строкой просмотрит весь скрипт и заменит предваренный символом '`' ASCII-текст на аналогичный текст в Shift-JIS...

 

Большое спасибо за списочек команд. :)

Изменено пользователем Serke (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

Большое спасибо за списочек команд.

Ммм... в дистрибутиве nScripter'а есть и более свежий ( [url="http://www.nscripter.com/nscr.lzh" target="_blank" rel="nofollow">http://www.nscripter.com/nscr.lzh[/url] ). На японском, но это лечится Atlas'ом...

Изменено пользователем WinKi-тян (смотреть историю редактирования)
Ссылка на комментарий
Поделиться на другие сайты

Ребят, извините что вмешиваюсь, но просмотрел тему и нифига не понял, о чем вы говорите. Я, конечно, глобально не в курсе, т.к. даже не знаю, что из себя все эти игры представляют... но родилось все же пару мыслей. И по такому случаю, не расскажете ли в трех словах, что конкретно требуется сделать? Пока я понял, что надо заставить яп. прогу понимать анг., рус. и др.

 

Это не то случаем? ->

Спойлер
Если под автором имеется ввиду непосредственный автор программы, то ему нужно просто в функции CreateFont() использовать нужный параметр, определяющий Charset. А если вы хотите исправить уже откомпилированный файл, то нужно найти место в программе, где вызывается функция CreateFont(), и подредактировать место, где определяются параметры для этой функции. Для этого лучше использовать дизассемблер и шестнацетиричный редактор. Дело в том, что у функции CreateFont очень много параметров, и для втоматического исправления кода нужен достаточно надежный анализатор этого кода. На создание такого анализатора вы потратите уйму времени, а на анализ кода при помощи дизассемлера требуется от силы полчасика.

 

Итак, приступим к изучению программы.

 

1. Если программа упакована каким либо пакером, то нужно её распаковать, вернее - это уже отдельная тема (взлом упакованой программы). А если нет, как в случае с антиспаем, то переходим к следующему шагу.

 

2. Нужно найти библиотеки импорта. Для этого можно использовать depends.exe от microsotf. Эта программа показывает все библиотеки и импортируемые программой функции из этих библиотек (в упакованном виде весит примерно 380 Кб, могу выслать). Нас интересует библиотека GDI32.DLL и функция CreateFont().

 

3. Теперь о функциях API создания шрифта. Это могут быть

CreateFontA() / CreateFontW()

CreateFontIndirectA() / CreateFontIndirectW()

CreateFontIndirectExA() / CreateFontIndirectExW()

Поясню: CreateFontA() и CreateFontW() это разные реализации одной и той же функции, т.е. они выполняют одну и ту же работу, только отличаются типом параметров. CreateFontA() в качестве строкового параметра принимает ANSI строки, а CreateFontW() - строки в Юникоде. С остальными функциями - так же.

У функции CreateFont() очень много параметров-14, а все остальные принимают только указатель на структуру, в которой уже собраны все эти парамеры.С антиспаем - используется CreateFontA().

 

4. Теперь про CreateFontA().

BOOL CreateFont(int nHeight, // определяет высоту шрифта в логических единицах

int nWidth, // определяет ширину шрифта, (обычно равен 0,ширина по умолчанию)

int nEscapement, // наклон в десятых градуса базовой линии текста (обычно 0)

int nOrientation, // наклон в десятых градуса базовой линии символа (обычно 0)

int nWeight, // вес символа (жирность) (обычно 400)

BYTE bItalic, // курсив (обычно 0)

BYTE bUnderline, // подчеркивание (обычно 0)

BYTE cStrikeOut, // зачеркивание (обычно 0)

BYTE nCharSet, // определяет национальность шрифта (то что нам нужно)

BYTE nOutPrecision, // без комментариев (можно 0)

BYTE nClipPrecision, // без комментариев (можно 0)

BYTE nQuality, // без комментариев (можно 0)

BYTE nPitchAndFamily, // без комментариев (можно 0)

LPCTSTR lpszFacename);// название шрифра (например "Arial")

 

5. Нашли нужную функцию в импорте - теперь нужно найти место в программе, где она вызывается, проанализировать её парамеры, и попытаться исправить nCharSet. Здесь нужен какой либо дизассемблер. В антиспае - nCharSet равен 0, что соответсвует америке. А нам нужен RUSSIAN_CHARSET, его значение 204 или 0CCh. Как исправить? Для передачи параметров функции используется стек, первым с стек помещается последний параметр функции (lpszFacename), последним - первый (nHeight), а затем call [адрес в таблице импорта].

Трудность исправления значений параметров заключается в том, что много нулевых параметров и оптимизатор кода при компиляции программы сделал следующим образом: обнулил какой то регистр (например ebx), а затем, когда требуется записать в стек 0, выполняется команда push ebx. Эта команда занимает только один байт. Команда push 204 занимает уже два байта, и просто так ей не вставишь (нет места). Я же сделал так: nPitchAndFamily не был нулевым, и на него тратилось два байта, я его обнулил (заменил на push ebx), а освободившийся байт использовал для nCharSet. При этом все параметры между ними сместились на один байт. Это я проделал в двух местах. Для этого нужен шестнадцатиричный редактор. И все - антиспай у меня стал показывать нормальный текст.

 

Всего хорошего. На описание того что я сделал потребовалось больше времени, чем на сам патч.

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
×
×
  • Создать...

Важная информация