First commit
This commit is contained in:
commit
5148b1182f
|
@ -0,0 +1,5 @@
|
|||
EXE_RESOURCE
|
||||
Pharaoh.exe
|
||||
Pharaoh_*.exe
|
||||
PharaohNew.exe
|
||||
PharaohResizer
|
|
@ -0,0 +1,7 @@
|
|||
PharaohResizer: PharaohResizer.c
|
||||
$(CC) -Os -ansi -pedantic $@.c -o $@ -llz4
|
||||
|
||||
clean:
|
||||
rm -f PharaohResizer
|
||||
|
||||
.PHONY: clean
|
|
@ -0,0 +1,568 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <lz4.h>
|
||||
|
||||
#define EXE_SIZE 2142208
|
||||
|
||||
#define MIN_WIDTH 1024
|
||||
#define MAX_WIDTH 7680
|
||||
#define MIN_HEIGHT 720
|
||||
#define MAX_HEIGHT 4320
|
||||
|
||||
unsigned long int widthOffsets[] =
|
||||
{
|
||||
0xcfa0a,
|
||||
0xcfda3
|
||||
};
|
||||
|
||||
unsigned long int heightOffsets[] =
|
||||
{
|
||||
0xcfa0f,
|
||||
0xcfdad
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
unsigned char exeFile[EXE_SIZE];
|
||||
|
||||
/* Patch a single byte. */
|
||||
void PatchByte(unsigned long int offset, unsigned char value)
|
||||
{
|
||||
exeFile[offset] = value;
|
||||
}
|
||||
|
||||
/* Patch an array of bytes in */
|
||||
void PatchBytes(unsigned long int offset, int count, unsigned char *bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
exeFile[offset+i] = bytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Patch a little-endian 32bit value in. */
|
||||
void PatchU32(unsigned long int offset, unsigned long int value)
|
||||
{
|
||||
exeFile[offset] = value & 0xFF;
|
||||
exeFile[offset+1] = (value >> 8) & 0xFF;
|
||||
exeFile[offset+2] = (value >> 16) & 0xFF;
|
||||
exeFile[offset+3] = (value >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
/* Helper function for Nopping out a region of code. */
|
||||
void NopBytes(unsigned long int offset, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
exeFile[offset+i] = 0x90;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sometimes we pad regions with non-nop bytes. int 3 (0xCC) is popular. */
|
||||
void PadBytes(unsigned long int offset, int count, unsigned char byte)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
exeFile[offset+i] = byte;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply all of the patches from the PharaohResizer
|
||||
* version to a raw Cleopatra exe (assuming DRM, etc,
|
||||
* skipped).
|
||||
*/
|
||||
void DoCrudeliosPatches()
|
||||
{
|
||||
unsigned char jmp_loc_56E331[] = {0xE9, 0x0B, 0xBB, 0x12, 0x00};
|
||||
unsigned char jmp_loc_56E37B[] = {0xE9, 0x84, 0x04, 0x09, 0x00, 0x90};
|
||||
unsigned char jmp_loc_56E35E[] = {0xE9, 0x11, 0x04, 0x09, 0x00, 0x90};
|
||||
unsigned char jmp_loc_56E491[] = {0xE9, 0xEE, 0x5B, 0x07, 0x00};
|
||||
unsigned char new_loc_51E96D[] = {
|
||||
0x7C, 0x1B, /* jl short locret_51E98F */
|
||||
0x52, 0x50, /* push edx | push eax */
|
||||
0xE8, 0x21, 0xFA, 0x04, 0x00, /* call sub_56E39C */
|
||||
0x58, 0x29, 0xD0, /* pop eax | sub eax, edx */
|
||||
0x83, 0xE8, 0x2A, /* sub eax, 42 */
|
||||
0xA3, 0x60, 0x3F, 0xF5, 0x00, /* mov dword_F53F60, eax */
|
||||
0x83, 0xE8, 0x78, /* sub eax, 120 */
|
||||
0xA3, 0x64, 0x3F, 0xF5, 0x00, /* mov dword_F53F64, eax */
|
||||
0x5A, 0xC3 /* pop edx | ret */
|
||||
};
|
||||
unsigned char sub_51E990_patch[] = {
|
||||
0x8B, 0x0D, 0xAC, 0x8D, 0xE3, 0x00, /* mov ecx, dword_E38DAC */
|
||||
0x6A, 0x09, /* push 9 */
|
||||
0x50, 0x51 /* push eax | push ecx */
|
||||
};
|
||||
unsigned char sub_51E990_patch2[] = { 0xE8, 0xA6, 0xFA, 0x04, 0x00, 0xC3 };
|
||||
unsigned char sub_51E990_patch3[] = { 0xE8, 0x6B, 0xFA, 0x04, 0x00, 0x0C3 };
|
||||
unsigned char jmp_loc_56E3C7[] = {0xE9, 0xAB, 0xE5, 0x04, 0x00};
|
||||
unsigned char jmp_loc_56E3DF[] = {0xE9, 0xF2, 0xEA, 0x03, 0x00, 0x90};
|
||||
unsigned char sub_56E24F[] = {
|
||||
0x53,
|
||||
0x56, 0xE8, 0x46, 0x01, 0x00, 0x00, 0x85, 0xD2,
|
||||
0x74, 0x74, 0x52, 0x51, 0x31, 0xD2, 0xA1, 0xAC,
|
||||
0x8D, 0xE3, 0x00, 0xBB, 0xA0, 0x02, 0x00, 0x00,
|
||||
0xF7, 0xFB, 0xF7, 0xEB, 0x05, 0x50, 0x01, 0x00,
|
||||
0x00, 0x8B, 0x1D, 0xE4, 0x67, 0xF5, 0x00, 0x59,
|
||||
0x01, 0xCB, 0x5A, 0x31, 0xF6, 0x8B, 0x0D, 0xB0,
|
||||
0x8D, 0xE3, 0x00, 0x83, 0xFA, 0x28, 0x7E, 0x11,
|
||||
0x83, 0xFA, 0x32, 0x7E, 0x07, 0xBE, 0x14, 0x00,
|
||||
0x00, 0x00, 0xEB, 0x05, 0xBE, 0x0A, 0x00, 0x00,
|
||||
0x00, 0x29, 0xD1, 0x01, 0xF1, 0x2D, 0x50, 0x01,
|
||||
0x00, 0x00, 0x3D, 0x50, 0x01, 0x00, 0x00, 0x7D,
|
||||
0x02, 0x31, 0xC0, 0x50, 0x51, 0x52, 0x50, 0x51,
|
||||
0x53, 0xB9, 0xB0, 0x5B, 0xF5, 0x00, 0xE8, 0xD5,
|
||||
0x02, 0xFD, 0xFF, 0x5A, 0x59, 0x58, 0x85, 0xF6,
|
||||
0x74, 0x08, 0x83, 0xEE, 0x0A, 0x83, 0xE9, 0x0A,
|
||||
0xEB, 0xE1, 0x85, 0xC0, 0x75, 0xAD, 0x5E, 0x5B,
|
||||
0xC3
|
||||
};
|
||||
unsigned char loc_56E2D3[] = {
|
||||
|
||||
0xE8, 0xB8, 0x02, 0xFD, 0xFF,
|
||||
0x53, 0xA1, 0xB0, 0x8D, 0xE3, 0x00, 0xBB, 0x48,
|
||||
0x03, 0x00, 0x00, 0x29, 0xD8, 0x8B, 0x0D, 0xE4,
|
||||
0x67, 0xF5, 0x00, 0x83, 0xC1, 0x08, 0x50, 0x51,
|
||||
0x6A, 0x00, 0x53, 0x51, 0xB9, 0xB0, 0x5B, 0xF5,
|
||||
0x00, 0xE8, 0x92, 0x02, 0xFD, 0xFF, 0x59, 0x58,
|
||||
0x81, 0xC3, 0x48, 0x03, 0x00, 0x00, 0x39, 0xC3,
|
||||
0x7C, 0xE4, 0x51, 0xE8, 0x8C, 0x00, 0x00, 0x00,
|
||||
0x59, 0x8B, 0x1D, 0xB0, 0x8D, 0xE3, 0x00, 0x81,
|
||||
0xEB, 0xE8, 0x03, 0x00, 0x00, 0x29, 0xD3, 0x6A,
|
||||
0x00, 0x53, 0x51, 0xB9, 0xB0, 0x5B, 0xF5, 0x00,
|
||||
0xE8, 0x63, 0x02, 0xFD, 0xFF, 0x5B, 0xC3
|
||||
};
|
||||
unsigned char loc_56E331[] = {
|
||||
0x52, 0xA1, 0xB0, 0x8D, 0xE3, 0x00, 0x8B,
|
||||
0x15, 0x10, 0x2A, 0x5D, 0x00, 0x83, 0xE8, 0x20,
|
||||
0x39, 0xC2, 0x7E, 0x02, 0x89, 0xD0, 0x5A, 0xE9,
|
||||
0xDA, 0x44, 0xED, 0xFF
|
||||
};
|
||||
unsigned char loc_56E35E[] = {
|
||||
0x31, 0xD2,
|
||||
0xA1, 0xAC, 0x8D, 0xE3, 0x00, 0xB9, 0x0F, 0x00,
|
||||
0x00, 0x00, 0x29, 0xC8, 0xF7, 0xF1, 0x50, 0xE8,
|
||||
0x28, 0x00, 0x00, 0x00, 0x50, 0xE9, 0xDC, 0xFB,
|
||||
0xF6, 0xFF
|
||||
};
|
||||
unsigned char loc_56E37B[] = {
|
||||
0x31, 0xD2, 0xA1, 0xAC, 0x8D,
|
||||
0xE3, 0x00, 0xB9, 0x0F, 0x00, 0x00, 0x00, 0x29,
|
||||
0xC8, 0xF7, 0xF1, 0x50, 0xE8, 0x0B, 0x00, 0x00,
|
||||
0x00, 0x83, 0xC0, 0x02, 0x50, 0xE9, 0x62, 0xFB,
|
||||
0xF6, 0xFF,
|
||||
};
|
||||
unsigned char sub_56E39C[] = {
|
||||
0x31, 0xD2, 0xA1, 0xB0,
|
||||
0x8D, 0xE3, 0x00, 0x2D, 0xA0, 0x00, 0x00, 0x00,
|
||||
0xB9, 0x3C, 0x00, 0x00, 0x00, 0xF7, 0xF1, 0x83,
|
||||
0xFA, 0x18, 0x7F, 0x06, 0xB9, 0x02, 0x00, 0x00,
|
||||
0x00, 0xC3, 0xB9, 0x03, 0x00, 0x00, 0x00, 0xC3
|
||||
};
|
||||
unsigned char loc_56E3C7[] = {
|
||||
0x50,
|
||||
0xE8, 0xCF, 0xFF, 0xFF, 0xFF, 0x58, 0x89, 0xC1,
|
||||
0x29, 0xD1, 0x89, 0x0D, 0x58, 0xB5, 0xD3, 0x00,
|
||||
0xE9, 0x57, 0x1A, 0xFB, 0xFF
|
||||
};
|
||||
unsigned char loc_56E3DF[] = {
|
||||
0xA1,
|
||||
0xB0, 0x8D, 0xE3, 0x00, 0x8B, 0x15, 0x10, 0x2A,
|
||||
0x5D, 0x00, 0x83, 0xE8, 0x20, 0x39, 0xC2, 0x7F,
|
||||
0x02, 0x89, 0xC2, 0xE9, 0xF6, 0x14, 0xFC, 0xFF
|
||||
};
|
||||
unsigned char loc_56E491[] = {
|
||||
0x8B, 0x15, 0x30, 0x8E, 0xE3, 0x00, 0x83,
|
||||
0xFA, 0x26, 0x7D, 0x05, 0xBA, 0x26, 0x00, 0x00,
|
||||
0x00, 0xC1, 0xE0, 0x04, 0x52, 0x83, 0xC2, 0x08,
|
||||
0x01, 0xC2, 0x3B, 0x15, 0xAC, 0x8D, 0xE3, 0x00,
|
||||
0x5A, 0x7F, 0x05, 0x83, 0xC2, 0x00, 0xEB, 0x05,
|
||||
0x83, 0xEA, 0x00, 0x29, 0xC2, 0x89, 0x15, 0x8C,
|
||||
0xDD, 0xEA, 0x00, 0xE8, 0xD4, 0xFE, 0xFF, 0xFF,
|
||||
0x8B, 0x0D, 0xB0, 0x8D, 0xE3, 0x00, 0x29, 0xD1,
|
||||
0x31, 0xD2, 0x3B, 0x15, 0x78, 0x3F, 0xF5, 0x00,
|
||||
0x75, 0x08, 0x81, 0xE9, 0xA2, 0x00, 0x00, 0x00,
|
||||
0xEB, 0x03, 0x83, 0xE9, 0x2A, 0x8B, 0x15, 0x34,
|
||||
0x8E, 0xE3, 0x00, 0x52, 0x83, 0xC2, 0x08, 0xA1,
|
||||
0x88, 0xDD, 0xEA, 0x00, 0xC1, 0xE0, 0x04, 0x01,
|
||||
0xC2, 0x39, 0xCA, 0x5A, 0x7F, 0x05, 0x83, 0xC2,
|
||||
0x00, 0xEB, 0x07, 0x89, 0xCA, 0x83, 0xEA, 0x08,
|
||||
0x29, 0xC2, 0x89, 0x15, 0x90, 0xDD, 0xEA, 0x00,
|
||||
0xE9, 0xC7, 0xA3, 0xF8, 0xFF
|
||||
};
|
||||
unsigned char sub_56E532[] = {
|
||||
0x53, 0x8B, 0x5C, 0x24, 0x10, 0x53,
|
||||
0x53, 0xFF, 0x74, 0x24, 0x14, 0xFF, 0x74, 0x24,
|
||||
0x14, 0xB9, 0xB0, 0x5B, 0xF5, 0x00, 0xE8, 0x45,
|
||||
0x00, 0xFD, 0xFF, 0x6A, 0x01, 0xE8, 0x4E, 0x0B,
|
||||
0xFB, 0xFF, 0x6A, 0x01, 0xE8, 0x27, 0x11, 0xFB,
|
||||
0xFF, 0x83, 0xC4, 0x08, 0x5B, 0x81, 0xC3, 0x1D,
|
||||
0x01, 0x00, 0x00, 0x3B, 0x1D, 0xAC, 0x8D, 0xE3,
|
||||
0x00, 0x7C, 0xCC, 0x5B, 0xC2, 0x0C, 0x00
|
||||
};
|
||||
unsigned char sub_56E5A6[] = {
|
||||
0xA1, 0xAC,
|
||||
0x8D, 0xE3, 0x00, 0x2D, 0x00, 0x03, 0x00, 0x00,
|
||||
0xD1, 0xF8, 0x50, 0xA1, 0xB0, 0x8D, 0xE3, 0x00,
|
||||
0x2D, 0x00, 0x04, 0x00, 0x00, 0xD1, 0xF8, 0x50,
|
||||
0xFF, 0x74, 0x24, 0x0C, 0xE8, 0xC7, 0xFF, 0xFC,
|
||||
0xFF, 0xC2, 0x0C, 0x00
|
||||
};
|
||||
|
||||
/* Patch a function call? */
|
||||
PatchU32(0x1A236, 0x15436C);
|
||||
PatchU32(0x1A8C7, 0x153CDB);
|
||||
PatchU32(0x1A8F3, 0x153CAF);
|
||||
PatchU32(0x1A964, 0x153C3E);
|
||||
PatchU32(0x1A9AA, 0x153BF8);
|
||||
PatchU32(0x1A9D1, 0x153BD1);
|
||||
PatchU32(0x1AB2F, 0x153A73);
|
||||
|
||||
/* Patch a comparison out */
|
||||
PatchByte(0x1E657, 0xEB); /*jmp*/
|
||||
|
||||
/* Patch a massive jump? */
|
||||
PatchBytes(0x42821, 5, jmp_loc_56E331);
|
||||
|
||||
/* Patch a jnz -> jl */
|
||||
PatchByte(0xDDEF0, 0x7C);
|
||||
/* ...and a jump in */
|
||||
PatchBytes(0xDDEF2, 6, jmp_loc_56E37B);
|
||||
|
||||
/* Patch a jnz -> jl */
|
||||
PatchByte(0xDDF42, 0x7C);
|
||||
/* ...and a jump in */
|
||||
PatchBytes(0xDDF48, 6, jmp_loc_56E35E);
|
||||
|
||||
/* Patch a jnz -> jl */
|
||||
PatchByte(0xF889C, 0x7C);
|
||||
/* ...and a jump in */
|
||||
PatchBytes(0xF889E, 5, jmp_loc_56E491);
|
||||
/* ...and nop out a bunch. */
|
||||
NopBytes(0xF88A3, 57);
|
||||
|
||||
/* Rewrite another functon. */
|
||||
PatchBytes(0x11E972, ARRAY_SIZE(new_loc_51E96D), new_loc_51E96D);
|
||||
|
||||
/* sub_51E990 changes: */
|
||||
/* jnz -> jl */
|
||||
PatchByte(0x11E99A, 0x7C);
|
||||
/* call target -> sub_56E24F */
|
||||
PatchU32(0x11E99D, 0x4F8AE);
|
||||
/* jnz -> jl */
|
||||
PatchByte(0x11E9BB, 0x7C);
|
||||
/* Modify setup for call to sub_4CD9D0 */
|
||||
PatchBytes(0x11E9BD, ARRAY_SIZE(sub_51E990_patch), sub_51E990_patch);
|
||||
NopBytes(0x11E9C7, 6);
|
||||
/* add eax, _0_ instead of 250 */
|
||||
PatchByte(0x11E9D9, 0);
|
||||
/* jnz -> jl */
|
||||
PatchByte(0x11EA67, 0x7C);
|
||||
/* call sub_56E532 and return */
|
||||
PatchBytes(0x11EA87, ARRAY_SIZE(sub_51E990_patch2), sub_51E990_patch2);
|
||||
NopBytes(0x11EA8D, 22);
|
||||
/* and again, call sub_56E532 and return */
|
||||
PatchBytes(0x11EAC2, ARRAY_SIZE(sub_51E990_patch3), sub_51E990_patch3);
|
||||
NopBytes(0x11EAC8, 22);
|
||||
|
||||
/* Another jnz -> jl */
|
||||
PatchByte(0x11EBB0, 0x7C);
|
||||
|
||||
/* Another one, but this time a longer encoding */
|
||||
PatchByte(0x11F4AD, 0x8C);
|
||||
|
||||
/* Another jnz -> jl */
|
||||
PatchByte(0x11FE15, 0x7C);
|
||||
/* Then a jmp loc_56E3C7 */
|
||||
PatchBytes(0x11FE17, 5, jmp_loc_56E3C7);
|
||||
NopBytes(0x11FE1C, 7);
|
||||
|
||||
/* sub_51FD60 patches: */
|
||||
/* A jnz -> jl */
|
||||
PatchByte(0x11FF3E, 0x7C);
|
||||
/* Patch call target -> sub_56E532 */
|
||||
PatchU32(0x11FF5C, 0x4E5D2);
|
||||
/* Another call target -> sub_56E532 */
|
||||
PatchU32(0x11FFBD, 0x4E571);
|
||||
|
||||
/* Another call target to sub_56E5A6 */
|
||||
PatchU32(0x120F95, 0x4D60D);
|
||||
|
||||
/* A massive jump to loc_56E3DF */
|
||||
PatchBytes(0x12F8E8, 6, jmp_loc_56E3DF);
|
||||
|
||||
/* jnz -> jl */
|
||||
PatchByte(0x136689, 0x8C);
|
||||
|
||||
/* A big jump to loc_56E2D3 */
|
||||
PatchByte(0x1366F5, 0xE9);
|
||||
PatchU32(0x1366F6, 0x37BD9);
|
||||
|
||||
/* Patch 1003 -> 1900 in a push statement */
|
||||
PatchU32(0x13712B, 1900);
|
||||
|
||||
/* Now patch in a bunch of custom functions and/or
|
||||
function fragments in the free space at the end
|
||||
of the .exe */
|
||||
|
||||
PadBytes(0x16E24D, 2, 0xCC);
|
||||
PatchBytes(0x16E24F, ARRAY_SIZE(sub_56E24F), sub_56E24F);
|
||||
|
||||
PadBytes(0x16E2D1, 2, 0xCC);
|
||||
/* FUNCTION CHUNK FOR sub_536670 */
|
||||
PatchBytes(0x16E2D3, ARRAY_SIZE(loc_56E2D3), loc_56E2D3);
|
||||
|
||||
PadBytes(0x16E32F, 2, 0xCC);
|
||||
/* FUNCTION CHUNK FOR sub_442800 */
|
||||
PatchBytes(0x16E331, ARRAY_SIZE(loc_56E331), loc_56E331);
|
||||
|
||||
/* FUNCTION CHUNK FOR sub_4DDF20 */
|
||||
PatchBytes(0x16E35E, ARRAY_SIZE(loc_56E35E), loc_56E35E);
|
||||
|
||||
PadBytes(0x16E37A, 1, 0xCC);
|
||||
/* FUNCTION CHUNK FOR sub_4DDEC0 */
|
||||
PatchBytes(0x16E37B, ARRAY_SIZE(loc_56E37B), loc_56E37B);
|
||||
|
||||
PadBytes(0x16E39A, 2, 0xCC);
|
||||
/* sub_56E39C */
|
||||
PatchBytes(0x16E39C, ARRAY_SIZE(sub_56E39C), sub_56E39C);
|
||||
|
||||
PadBytes(0x16E3C0, 7, 0xCC);
|
||||
/* FUNCTION CHUNK FOR sub_51FD60 */
|
||||
PatchBytes(0x16E3C7, ARRAY_SIZE(loc_56E3C7), loc_56E3C7);
|
||||
|
||||
PadBytes(0x16E3DD, 2, 0xCC);
|
||||
/* FUNCTION CHUNK FOR sub_52F8B0 */
|
||||
PatchBytes(0x16E3DF, ARRAY_SIZE(loc_56E3DF), loc_56E3DF);
|
||||
|
||||
/* FUNCTION CHUNK FOR sub_4F7E50 */
|
||||
PatchBytes(0x16E491, ARRAY_SIZE(loc_56E491), loc_56E491);
|
||||
|
||||
/* sub_56E532 */
|
||||
PatchBytes(0x16E532, ARRAY_SIZE(sub_56E532), sub_56E532);
|
||||
|
||||
/* sub_56E5A6 */
|
||||
PatchBytes(0x16E5A6, ARRAY_SIZE(sub_56E5A6), sub_56E5A6);
|
||||
}
|
||||
|
||||
void PatchResolution(int width, int height)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(widthOffsets); ++i)
|
||||
{
|
||||
PatchU32(widthOffsets[i], width);
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(heightOffsets); ++i)
|
||||
{
|
||||
PatchU32(heightOffsets[i], height);
|
||||
}
|
||||
}
|
||||
|
||||
/* Patch in some code to auto-detect the resolution */
|
||||
void PatchAutoResolution()
|
||||
{
|
||||
unsigned char call_SetScreenSize[] = {
|
||||
0xE8, 0x57, 0x03, 0x00, 0x00, /* call SetScreenSize */
|
||||
0xEB, 0x20 /* jmp loc_4CFA2B */
|
||||
};
|
||||
unsigned char new_SetScreenSize[] = {
|
||||
0x8B, 0x2D, 0xA0, 0xF1, 0x56, 0x00, /* mov ebp, ds:GetSystemMetrics */
|
||||
0x6A, 0x00, /* push SM_CXSCREEN (0) */
|
||||
0xFF, 0xD5, /* call ebp (GetSystemMetrics) */
|
||||
0xA3, 0xB0, 0x8D, 0xE3, 0x00, /* mov ScreenWidth, eax */
|
||||
0x6A, 0x01, /* push SM_CYSCREEN (1) */
|
||||
0xFF, 0xD5, /* call ebp (GetSystemMetrics) */
|
||||
0xA3, 0xAC, 0x8D, 0xE3, 0x00, /* mov ScreenHeight, eax */
|
||||
0xC3 /* ret */
|
||||
};
|
||||
|
||||
/* Don't default to 800x600: jnz -> jmp */
|
||||
PatchByte(0xCF9F0, 0xEB);
|
||||
|
||||
PatchBytes(0xCFA04, ARRAY_SIZE(call_SetScreenSize), call_SetScreenSize);
|
||||
|
||||
NopBytes(0xCFA0B, 32);
|
||||
|
||||
PatchBytes(0xCFD60, ARRAY_SIZE(new_SetScreenSize), new_SetScreenSize);
|
||||
}
|
||||
|
||||
int ValidateResolution(int width, int height)
|
||||
{
|
||||
int valid = 1;
|
||||
if (width & 3)
|
||||
{
|
||||
fprintf(stderr, "The width %d is not a multiple of 4.\n", width);
|
||||
fprintf(stderr, "Pharaoh requires the resolution's width to be divisible by 4.\n");
|
||||
valid = 0;
|
||||
}
|
||||
|
||||
if (width < MIN_WIDTH)
|
||||
{
|
||||
fprintf(stderr, "The width %d is less than %d.\n", width, MIN_WIDTH);
|
||||
fprintf(stderr, "The selected width must be at least %d pixels.\n", MIN_WIDTH);
|
||||
valid = 0;
|
||||
}
|
||||
|
||||
if (width > MAX_WIDTH)
|
||||
{
|
||||
fprintf(stderr, "The width %d is greater than %d.\n", width, MAX_WIDTH);
|
||||
fprintf(stderr, "The selected width must be no greater than %d pixels.\n", MAX_WIDTH);
|
||||
valid = 0;
|
||||
}
|
||||
|
||||
if (height & 3)
|
||||
{
|
||||
fprintf(stderr, "The height %d is not a multiple of 4.\n", height);
|
||||
fprintf(stderr, "Pharaoh requres the resolution's height to be divisible by 4.\n");
|
||||
valid = 0;
|
||||
}
|
||||
|
||||
if (height < MIN_HEIGHT)
|
||||
{
|
||||
fprintf(stderr, "The height %d is less than %d.\n", height, MIN_HEIGHT);
|
||||
fprintf(stderr, "The selected height must be at least %d pixels.\n", MIN_HEIGHT);
|
||||
valid = 0;
|
||||
}
|
||||
|
||||
if (height > MAX_HEIGHT)
|
||||
{
|
||||
fprintf(stderr, "The height %d is greater than %d.\n", height, MAX_HEIGHT);
|
||||
fprintf(stderr, "The selected height must be no greater than %d pixels.\n", MAX_HEIGHT);
|
||||
valid = 0;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *inName;
|
||||
const char *outName;
|
||||
int width;
|
||||
int height;
|
||||
FILE *inFile;
|
||||
FILE *outFile;
|
||||
size_t compSize;
|
||||
int retVal;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("%s: Run Pharaoh+Cleopatra at different resolutions\n", argv[0]);
|
||||
printf("\n");
|
||||
printf("Usage:\n");
|
||||
printf("\t%s input [output] [width] [height]\n", argv[0]);
|
||||
printf("\tinput: the Cleopatra 2.1 .exe file, or extracted EXE_RESOURCE from PharaohResizer\n");
|
||||
printf("\t[output]: The .exe file to write, defaults to PharaohNew.exe\n");
|
||||
printf("\t[width]: The width of the resolution to use, otherwise autodetected\n");
|
||||
printf("\t[height]: The height of the resolution to use, otherwise autodetected\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
inName = argv[1];
|
||||
outName = (argc >= 3)?argv[2]:"PharaohNew.exe";
|
||||
width = (argc >= 4)?atoi(argv[3]):0;
|
||||
height = (argc >= 5)?atoi(argv[4]):0;
|
||||
|
||||
/* Validate the resolution before we do anything further. */
|
||||
if ((width || height) && !ValidateResolution(width, height))
|
||||
{
|
||||
/* ValidateResolution prints its own errors. */
|
||||
return 7;
|
||||
}
|
||||
|
||||
inFile = fopen(inName, "rb");
|
||||
if (!inFile)
|
||||
{
|
||||
fprintf(stderr, "Couldn't open input file \"%s\"\n", inName);
|
||||
return 2;
|
||||
}
|
||||
|
||||
outFile = fopen(outName, "wb");
|
||||
if (!outFile)
|
||||
{
|
||||
fprintf(stderr, "Couldn't open output file \"%s\"\n", outName);
|
||||
fprintf(stderr, "Check that the path is correct and is writable.\n");
|
||||
fclose(inFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
fseek(inFile, 0, SEEK_END);
|
||||
compSize = ftell(inFile);
|
||||
fseek(inFile, 0, SEEK_SET);
|
||||
|
||||
if (compSize == EXE_SIZE)
|
||||
{
|
||||
/* We are patching an original Cleopatra 2.1 .exe */
|
||||
if (fread(exeFile, EXE_SIZE, 1, inFile) != 1)
|
||||
{
|
||||
fprintf(stderr, "Couldn't read input file \"%s\"\n", inName);
|
||||
fclose(inFile);
|
||||
fclose(outFile);
|
||||
return 5;
|
||||
}
|
||||
fclose(inFile);
|
||||
|
||||
/* As we're using an original .exe, we need to patch it. */
|
||||
DoCrudeliosPatches();
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *compData = malloc(compSize);
|
||||
if (!compData)
|
||||
{
|
||||
fprintf(stderr, "Not enough memory to load compressed file \"%s\"\n", inName);
|
||||
fprintf(stderr, "Is it mysteriously enormous? It appears to be %lu MiB.\n", compSize / (1024 * 1024));
|
||||
fclose(inFile);
|
||||
fclose(outFile);
|
||||
return 4;
|
||||
}
|
||||
if (fread(compData, compSize, 1, inFile) != 1)
|
||||
{
|
||||
fprintf(stderr, "Couldn't read input file \"%s\"\n", inName);
|
||||
fclose(inFile);
|
||||
fclose(outFile);
|
||||
return 5;
|
||||
}
|
||||
fclose(inFile);
|
||||
|
||||
retVal = LZ4_decompress_safe((char *) compData, (char *) exeFile, compSize, EXE_SIZE);
|
||||
|
||||
if (retVal < 1)
|
||||
{
|
||||
fprintf(stderr, "Couldn't decompress input file \"%s\"\n", inName);
|
||||
fprintf(stderr, "Check that it's the correct resource extracted from PharaohResizer.exe\n");
|
||||
fprintf(stderr, "You can extract it from PharaohResizer.exe with:\n");
|
||||
fprintf(stderr, "\twrestool PharaohResizer.exe -x --type='EXECUTABLE' --name=101\n");
|
||||
fprintf(stderr, "Alternatively, make sure you're providing a Cleopatra 2.1 English .exe file\n");
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
if (width && height)
|
||||
{
|
||||
/* Patch the user's width and height in. */
|
||||
PatchResolution(width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write some code to autodetect the resolution. */
|
||||
PatchAutoResolution();
|
||||
}
|
||||
|
||||
if (fwrite(exeFile, EXE_SIZE, 1, outFile) != 1)
|
||||
{
|
||||
fprintf(stderr, "Couldn't write output executable \"%s\"\n", outName);
|
||||
fprintf(stderr, "Have you run out of disk space or something?\n");
|
||||
fclose(outFile);
|
||||
return 8;
|
||||
}
|
||||
fclose(outFile);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
Pharaoh Resizer in ANSI C, by Matteo Bini.
|
||||
Created in 2023. Public domain and free for any use.
|
||||
|
||||
This is a version of Pharaoh Resizer written in ANSI C, based on the
|
||||
GNU/Linux version of the same program made by sulix [1], which itself
|
||||
was based on the original Pharaoh Resizer source code by crudelios [2].
|
||||
|
||||
[1] https://github.com/sulix/PharaohResizer/tree/linux
|
||||
[2] https://github.com/crudelios/PharaohResizer
|
||||
|
||||
The original readme.txt file by crudelios follows below.
|
||||
|
||||
Pharaoh Resizer, by crudelios.
|
||||
Created in 2016. Public domain and free for any use.
|
||||
|
||||
This program was created in order to help people resize their Pharaoh + Cleopatra to widescreen.
|
||||
|
||||
Currently it supports an horizontal resolution from 1024 to 7680 and a vertical resolution from 720
|
||||
to 4320 (allowing for perfect usage on 8k screens!).
|
||||
|
||||
In order to compile the source code, you'll need to include the LZ4 library. LZ4 is a very fast
|
||||
compression algorithm which is used to decompress my edited Pharaoh.exe that is included with
|
||||
this program. Check the LZ4 license below in order to download it:
|
||||
|
||||
LZ4 - Fast LZ compression algorithm
|
||||
Copyright (C) 2011-2012, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
Loading…
Reference in New Issue