📄 cbinmod.cpp
字号:
goto exit;
}
FILESentry *pFileList = new FILESentry[TOC.numfiles];
if(!pFileList){
dprintf("Error allocated space for files list containing %d files\n", TOC.numfiles);
goto exit;
}
DWORD files_section_offset = pTOC + sizeof(ROMHDR) + sizeof(TOCentry) * TOC.nummods;
// read FILESEntry list
if(!AccessBinFile((BYTE*)pFileList,
files_section_offset,
sizeof(FILESentry) * TOC.numfiles,
dwROMOffset,
false)){
dprintf("Couldn't read file list\n");
goto exit;
}
for(int i = 0; i < (int)TOC.numfiles; i++){
if(!AccessBinFile(pBuffer, (DWORD)pFileList[i].lpszFileName, 0, dwROMOffset, false)){
dprintf("Couldn't read file name for file %d\n", i);
if(i)
dprintf("previous file was %s\n", pBuffer);
goto exit;
}
if(strcmp((char*)pBuffer, name.c_str()) == 0)
{
bool compressed = false;
if(pFileList[i].nRealFileSize != pFileList[i].nCompFileSize) compressed = true;
DWORD size = 0;
if(compressed)
size = pFileList[i].nCompFileSize;
else
size = pFileList[i].nRealFileSize;
dprintf("Found '%s' in the image! - located at %08x, size %08x %s\n", name.c_str(), pFileList[i].ulLoadOffset, size, compressed ? "compressed" : "uncompressed");
BYTE *cbuffer = new BYTE[pFileList[i].nCompFileSize];
if(!cbuffer){
dprintf("Error: failed allocating buffer\n");
goto exit;
}
if(!AccessBinFile((BYTE*)cbuffer,
pFileList[i].ulLoadOffset,
pFileList[i].nCompFileSize,
dwROMOffset,
false)){
dprintf("Error: failed reading reading file\n");
goto exit;
}
if(compressed){
// compress the data
BYTE *uncompressed_data = new BYTE[pFileList[i].nRealFileSize];
DWORD uncompressed_size;
DWORD page_size = 0x1000;
if(!uncompressed_data){
dprintf("Error: failed allocating buffer\n");
goto exit;
}
char *m_name = "compress.dll";
HMODULE m_hcomp = LoadLibrary(m_name);
if(!m_hcomp){
dprintf("Error: LoadLibrary() failed to load '%s': %d\n", m_name, GetLastError());
return false;
}
CEDECOMPRESS cedecompress = (CEDECOMPRESS)GetProcAddress(m_hcomp, "CEDecompress");
if(!cedecompress){
dprintf("Error: GetProcAddress() failed to find 'CEDecompress' in '%s': %d\n", m_name, GetLastError());
FreeLibrary(m_hcomp);
return false;
}
dprintf("Assuming pagesize of %08x for decompression!\n", page_size);
uncompressed_size = cedecompress(cbuffer,
pFileList[i].nCompFileSize,
uncompressed_data,
pFileList[i].nRealFileSize,
0,
1,
page_size);
FreeLibrary(m_hcomp);
// if success
if(uncompressed_size != pFileList[i].nRealFileSize){
dprintf("Error: decompression failed\n");
goto exit;
}
cbuffer = uncompressed_data;
}
// open and write file
HANDLE hOut = CreateFile(_file.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, 0);
if(hOut == INVALID_HANDLE_VALUE){
dprintf("failed to open %s for output\n", _file.c_str());
goto exit;
}
DWORD cb = 0;
if(!WriteFile(hOut, cbuffer, pFileList[i].nRealFileSize, &cb, NULL)){
dprintf("Error: failed to write file data\n");
goto exit;
}
dprintf("File extracted!\n");
ret = true;
goto exit;
break;
}
}
goto NextRegion;
EndOfRegions:
dprintf("Error: File not found in image\n");
exit:
return ret;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool CBinMod::AccessBinFile(PBYTE buffer, DWORD dwAddress, DWORD dwLength, DWORD dwROMOffsetRead, bool bWrite)
{
DWORD dwBytes;
BOOL fRet;
DWORD i;
DWORD dwDiff;
FlushFileBuffers(hFile);
//
// Adjust if needed
//
dwAddress += dwROMOffsetRead;
for (i = 0; i < dwNumRecords; i++) {
if(Records[i].dwStartAddress <= dwAddress &&
Records[i].dwStartAddress + Records[i].dwLength >= (dwAddress + dwLength))
{
//
// Offset into the record.
//
dwDiff = dwAddress - Records[i].dwStartAddress;
my_SetFilePointer(hFile, Records[i].dwFilePointer + dwDiff, NULL, FILE_BEGIN);
if(bWrite)
{
if(dwLength)
{
fRet = my_WriteFile(hFile, buffer, dwLength, &dwBytes, NULL);
if(!fRet || dwBytes != dwLength)
{
return false;
}
}
else
{
do
{
fRet = my_WriteFile(hFile, buffer, 1, &dwBytes, NULL);
}
while (*buffer++);
}
if(!ReWriteCheckSum(dwAddress))
{
dprintf("Error: Failed writing new checksum\n");
return false;
}
}
else
{
if (dwLength)
{
fRet = my_ReadFile(hFile, buffer, dwLength, &dwBytes, NULL);
if (!fRet || dwBytes != dwLength)
{
return false;
}
}
else
{
do
{
fRet = my_ReadFile(hFile, buffer, 1, &dwBytes, NULL);
}
while (*buffer++);
}
}
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool CBinMod::ReWriteCheckSum(DWORD dwAddress)
{
DWORD dwBytes;
DWORD i, j;
UCHAR c;
DWORD dwCheckSum = 0;
for(i = 0; i < dwNumRecords; i++)
{
if(Records[i].dwStartAddress <= dwAddress &&
Records[i].dwStartAddress + Records[i].dwLength > dwAddress)
{
dprintf("Original record checksum: 0x%x\n", Records[i].dwChecksum);
// point to record
my_SetFilePointer(hFile, Records[i].dwFilePointer, NULL, FILE_BEGIN);
// calculate checksum
for (j = 0; j < Records[i].dwLength; j++) {
if (!my_ReadFile(hFile, &c, 1, &dwBytes, NULL) || (dwBytes != 1)) {
return false;
}
dwCheckSum += c;
}
dprintf("New record checksum: 0x%x\n", dwCheckSum);
// Now write the checksum
my_SetFilePointer(hFile, Records[i].dwFilePointer - 4, NULL, FILE_BEGIN);
if (!my_WriteFile(hFile, &dwCheckSum, 4, &dwBytes, NULL) || (dwBytes != 4)){
return false;
}
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool CBinMod::ComputeRomOffset(DWORD &state)
{
DWORD i;
bool fFoundIt = false;
bool fRet;
DWORD dwROMOffsetRead;
DWORD header[2] = {0};
ROMHDR *dwpTOC = 0;
for (i = state; i < dwNumRecords; i++)
{
//
// no pTOC and not an 8 byte record... skip
//
if(!dwpTOC)
{
if(Records[i].dwLength != 8)
continue;
//
// check for signature and pTOC
//
fRet = AccessBinFile((BYTE*)header, Records[i].dwStartAddress, 8, 0, false);
if(!fRet || header[0] != ROM_SIGNATURE)
continue;
//
// set pTOC and save current search and start record search over
//
dwpTOC = (ROMHDR*)header[1];
state = i + 1;
i = 0;
}
//
// Check for potential TOC records
//
if (Records[i].dwLength == sizeof(ROMHDR))
{
//
// If this _IS_ the TOC record, compute the ROM Offset.
//
dwROMOffsetRead = Records[i].dwStartAddress - (DWORD)dwpTOC;
dprintf("Checking record #%d for potential TOC (ROMOFFSET = 0x%08X)\n", i, dwROMOffsetRead);
//
// Read out the record to verify. (unadjusted)
//
fRet = AccessBinFile(pBuffer, Records[i].dwStartAddress, sizeof(ROMHDR), 0, false);
if (fRet)
{
ROMHDR *pTOCLoc = (ROMHDR *)pBuffer;
if(pTOCLoc->physfirst > (DWORD)dwpTOC || pTOCLoc->physlast < (DWORD)dwpTOC){
// dprintf("NOTICE! Record %d looked like a TOC at 0x%08x except Phys first = 0x%08X, and Phys last = 0x%08X\r\n", i, dwpTOC, pTOC->physfirst, pTOC->physlast);
continue;
}
if((pTOCLoc->physfirst >= (dwImageStart - dwROMOffsetRead)) &&
(pTOCLoc->physlast <= (dwImageStart - dwROMOffsetRead) + dwImageLength))
{
//
// Extra sanity check...
//
if((DWORD)(HIWORD(pTOCLoc->dllfirst) << 16) <= pTOCLoc->dlllast &&
(DWORD)(LOWORD(pTOCLoc->dllfirst) << 16) <= pTOCLoc->dlllast)
{
dprintf("Found pTOC = 0x%08x\n", (DWORD)dwpTOC);
fFoundIt = true;
break;
}
else
{
dprintf("NOTICE! Record %d looked like a TOC except DLL first = 0x%08X, and DLL last = 0x%08X\r\n", i, pTOCLoc->dllfirst, pTOCLoc->dlllast);
}
}
}
}
if(i == dwNumRecords - 1)
{
i = state - 1;
dwpTOC = 0;
}
}
if (fFoundIt)
{
dwROMOffset = dwROMOffsetRead;
pTOC = (DWORD)dwpTOC;
dprintf("rom offset = 0x%08X\n", dwROMOffset);
return true;
}
dwROMOffset = 0;
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD CBinMod::FindHole(DWORD size, ROMHDR *pToc){
for(DWORD i = dwNumRecords - 3; i; i--)
{
if(Records[i].dwStartAddress > pToc->physfirst + dwROMOffset &&
Records[i].dwStartAddress + Records[i].dwLength < pToc->physlast + dwROMOffset)
{
if(Records[i + 1].dwStartAddress - (Records[i].dwStartAddress + Records[i].dwLength) >= size)
{
dprintf("Found probable hole at end of record %d\n", i);
// shift end of image down to allow appending to this record.
DWORD insertion_point = SetFilePointer(hFile,
Records[i].dwFilePointer + Records[i].dwLength,
NULL,
FILE_BEGIN);
if(insertion_point == INVALID_SET_FILE_POINTER){
dprintf("Error: failed setting file pointer\n");
goto exit;
}
DWORD shift_size = my_GetFileSize(hFile, NULL) - insertion_point;
BYTE *buffer = (BYTE*)new BYTE[shift_size];
if(!buffer){
dprintf("Error: failed allocating buffer\n");
goto exit;
}
DWORD cb = 0;
if(!my_ReadFile(hFile, buffer, shift_size, &cb, NULL)){
dprintf("Error: failed reading shift data\n");
goto exit;
}
DWORD shift_point = my_SetFilePointer(hFile,
insertion_point + size,
NULL,
FILE_BEGIN);
if(shift_point == INVALID_SET_FILE_POINTER){
dprintf("Error: failed setting file pointer\n");
goto exit;
}
if(!my_WriteFile(hFile, buffer, shift_size, &cb, NULL)){
dprintf("Error: failed to write shifted data\n");
goto exit;
}
DWORD insertion_address = Records[i].dwStartAddress + Records[i].dwLength + dwROMOffset;
// checksum will get updated with data write but length needs to be fudged or write will fail.
Records[i].dwLength += size;
DWORD record_point = my_SetFilePointer(hFile,
Records[i].dwFilePointer - 3 * sizeof(DWORD),
NULL,
FILE_BEGIN);
if(record_point == INVALID_SET_FILE_POINTER){
dprintf("Error: failed setting file pointer\n");
goto exit;
}
if(!my_WriteFile(hFile, &Records[i], 3 * sizeof(DWORD), &cb, NULL)){
dprintf("Error: failed writing record header\n");
goto exit;
}
return insertion_address;
}
}
}
exit:
return 0;
}
void CBinMod::dprintf(char *message, ...){
va_list ap;
va_start(ap, message);
if(fpLog)
vfprintf(fpLog, message, ap);
else
vprintf(message, ap);
va_end(ap);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -