[saco] Implement and match file hook functions

This commit is contained in:
RD42 2024-04-17 22:48:54 +08:00
parent 3b7b6e47c5
commit 33cb3d22f7
3 changed files with 334 additions and 11 deletions

View File

@ -2,6 +2,11 @@
#include <windows.h>
#include "detours.h"
#include "filehooks.h"
#include "filesystem.h"
#include "filechecks.h"
#include "runutil.h"
#include "checksums.h"
#include "game/game.h"
//----------------------------------------------------------
@ -15,10 +20,84 @@ def_CloseHandle Real_CloseHandle = NULL;
def_GetFileType Real_GetFileType = NULL;
def_ShowCursor Real_ShowCursor = NULL;
extern CFileSystem *pFileSystem;
extern CGame *pGame;
ARCH_FILE_RECORD OpenArchRecords[MAX_OPEN_ARCH_FILES];
BOOL bArchRecordSlotState[MAX_OPEN_ARCH_FILES];
BOOL bFileHooksInstalled = FALSE;
int iCustomHandle=CUSTOM_HANDLE_BASE;
UINT dwHandlingDigest[] = { 0x11C714FD, 0x0A46694E, 0x7AEC2920, 0x2100E2E4, 0x94F7372E }; // handling.cfg
UINT dwWeaponDigest[] = { 0x0B85A2AD, 0x344BDAE1, 0xA19471D5, 0x7D49D3E9, 0x7DDE6CBE }; // weapon.dat
UINT dwMeleeDigest[] = { 0x7C425B89, 0xF67763C0, 0xA2E49F0E, 0x93EBF8D2, 0x0E842901 }; // melee.dat
char * FileNameOnly(char *sz);
char * ExtensionOnly(char *sz);
char* strtolower(char* sz);
void CheckFileNameHash(UINT *pDigest);
//----------------------------------------------------------
BOOL IsCustomFileHandle(DWORD handle)
{
if(handle >= CUSTOM_HANDLE_BASE && handle < CUSTOM_HANDLE_LIMIT) {
return TRUE;
}
return FALSE;
}
//----------------------------------------------------------
int FindUnusedArchRecordIndex()
{
int x=0;
while(x!=MAX_OPEN_ARCH_FILES) {
if(bArchRecordSlotState[x] == FALSE) {
return x;
}
x++;
}
return (-1);
}
//----------------------------------------------------------
int FindArchRecordIndexFromHandle(HANDLE hFile)
{
int x=0;
while(x!=MAX_OPEN_ARCH_FILES) {
if(bArchRecordSlotState[x] == TRUE) {
if(OpenArchRecords[x].hHandle == hFile) {
return x;
}
}
x++;
}
return (-1);
}
//----------------------------------------------------------
HANDLE CreateArchRecord(DWORD dwFileIndex)
{
int iArchRecordIndex = FindUnusedArchRecordIndex();
if(iArchRecordIndex == (-1)) return 0;
bArchRecordSlotState[iArchRecordIndex] = TRUE;
OpenArchRecords[iArchRecordIndex].hHandle = (HANDLE)iCustomHandle;
iCustomHandle+=2;
OpenArchRecords[iArchRecordIndex].dwReadPosition = 0;
OpenArchRecords[iArchRecordIndex].dwFileSize = pFileSystem->GetFileSize(dwFileIndex);
OpenArchRecords[iArchRecordIndex].pbyteDataStart = pFileSystem->GetFileData(dwFileIndex);
OpenArchRecords[iArchRecordIndex].pbyteDataCurrent = OpenArchRecords[iArchRecordIndex].pbyteDataStart;
return OpenArchRecords[iArchRecordIndex].hHandle;
}
//----------------------------------------------------------
@ -27,12 +106,40 @@ HANDLE WINAPI Arch_CreateFileA( LPCTSTR lpFileName,DWORD dwDesiredAccess,
DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile )
{
// TODO: Arch_CreateFileA
#ifdef _DEBUG
/*
char szBuffer[FILENAME_MAX];
sprintf(szBuffer, "CreateFileA: %s\n", lpFileName);
OutputDebugString(szBuffer);
*/
#endif
return Real_CreateFileA(lpFileName,dwDesiredAccess,dwShareMode,
DWORD dwFileIndex = pFileSystem->GetFileIndex(FileNameOnly((PCHAR)lpFileName));
HANDLE ret=0;
if(dwFileIndex != FS_INVALID_FILE)
{
// The request file is in the archive, so we should return the handle.
ret = CreateArchRecord(dwFileIndex);
CHAR szFileName[MAX_PATH+1];
strcpy(szFileName, FileNameOnly((PCHAR)lpFileName));
strtolower(szFileName);
UINT digest[5];
CalcSHA1(szFileName, strlen(szFileName), digest);
CheckFileNameHash(digest);
}
else
{
// Don't check if it's in the archive
ret = Real_CreateFileA(lpFileName,dwDesiredAccess,dwShareMode,
lpSecurityAttributes,dwCreationDisposition,dwFlagsAndAttributes,hTemplateFile);
}
return ret;
}
//----------------------------------------------------------
HANDLE WINAPI Arch_CreateFileW( WORD * lpFileName,DWORD dwDesiredAccess,
@ -40,10 +147,21 @@ HANDLE WINAPI Arch_CreateFileW( WORD * lpFileName,DWORD dwDesiredAccess,
DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile )
{
// TODO: Arch_CreateFileW (unused)
#ifdef _DEBUG
/*
wchar_t wszBuffer[FILENAME_MAX];
swprintf(wszBuffer, L"CreateFileW: %s\n", lpFileName);
OutputDebugStringW(wszBuffer);
*/
#endif
return Real_CreateFileW(lpFileName,dwDesiredAccess,dwShareMode,
HANDLE ret=Real_CreateFileW(lpFileName,dwDesiredAccess,dwShareMode,
lpSecurityAttributes,dwCreationDisposition,dwFlagsAndAttributes,hTemplateFile);
if (IsCheckableFile(ExtensionOnly((PCHAR)lpFileName)))
{
CheckFileHash(GetFileNameHash(strtolower(FileNameOnly((PCHAR)lpFileName))), ret);
}
return ret;
}
//----------------------------------------------------------
@ -53,7 +171,68 @@ BOOL WINAPI Arch_ReadFile( HANDLE hFile,LPVOID lpBuffer,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped )
{
// TODO: Arch_ReadFile
int iArch=0;
HANDLE hEvent=0;
if( IsCustomFileHandle((DWORD)hFile) &&
((iArch = FindArchRecordIndexFromHandle(hFile)) != (-1)))
{
//char s[256];
//sprintf(s,"ReadFile(0x%X)",hFile);
//OutputDebugString(s);
DWORD dwFileSize = OpenArchRecords[iArch].dwFileSize;
DWORD dwNumBytesRead;
if(lpOverlapped) {
OpenArchRecords[iArch].dwReadPosition = lpOverlapped->Offset;
OpenArchRecords[iArch].pbyteDataCurrent =
OpenArchRecords[iArch].pbyteDataStart + lpOverlapped->Offset;
hEvent = lpOverlapped->hEvent;
}
// First condition: EOF
if(OpenArchRecords[iArch].dwReadPosition >= dwFileSize)
{
if(lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
if(hEvent) SetEvent(hEvent);
SetLastError(ERROR_HANDLE_EOF);
return TRUE;
}
DWORD dwEndPoint = (nNumberOfBytesToRead + OpenArchRecords[iArch].dwReadPosition);
// Second condition: Read will exceed or match EOF
if( dwEndPoint >= dwFileSize ) {
DWORD dwOverHang = dwEndPoint - dwFileSize;
dwNumBytesRead = nNumberOfBytesToRead - dwOverHang;
memcpy(lpBuffer,OpenArchRecords[iArch].pbyteDataCurrent,dwNumBytesRead);
OpenArchRecords[iArch].pbyteDataCurrent += dwNumBytesRead;
OpenArchRecords[iArch].dwReadPosition += dwNumBytesRead;
if(lpNumberOfBytesRead) *lpNumberOfBytesRead = dwNumBytesRead;
if(hEvent) SetEvent(hEvent);
SetLastError(ERROR_HANDLE_EOF);
return TRUE;
}
// Read will not exceed EOF
memcpy(lpBuffer,OpenArchRecords[iArch].pbyteDataCurrent,nNumberOfBytesToRead);
dwNumBytesRead = nNumberOfBytesToRead;
OpenArchRecords[iArch].pbyteDataCurrent += dwNumBytesRead;
OpenArchRecords[iArch].dwReadPosition += dwNumBytesRead;
if(lpNumberOfBytesRead) *lpNumberOfBytesRead = dwNumBytesRead;
if(hEvent) SetEvent(hEvent);
return TRUE;
}
return Real_ReadFile(hFile,lpBuffer,nNumberOfBytesToRead,
lpNumberOfBytesRead,lpOverlapped);
@ -63,8 +242,19 @@ BOOL WINAPI Arch_ReadFile( HANDLE hFile,LPVOID lpBuffer,
DWORD WINAPI Arch_GetFileSize( HANDLE hFile, PDWORD pdwSize )
{
// TODO: Arch_GetFileSize
int iArch;
if( IsCustomFileHandle((DWORD)hFile) &&
((iArch = FindArchRecordIndexFromHandle(hFile)) != (-1)))
{
//char s[256];
//sprintf(s,"GetFileSize(0x%X)",hFile);
//OutputDebugString(s);
if (pdwSize)
*pdwSize = 0;
return OpenArchRecords[iArch].dwFileSize;
}
return Real_GetFileSize(hFile,pdwSize);
}
@ -73,8 +263,30 @@ DWORD WINAPI Arch_GetFileSize( HANDLE hFile, PDWORD pdwSize )
DWORD WINAPI Arch_SetFilePointer( HANDLE hFile,LONG lDistanceToMove,
PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod )
{
// TODO: Arch_SetFilePointer
int iArch;
if( IsCustomFileHandle((DWORD)hFile) &&
((iArch = FindArchRecordIndexFromHandle(hFile)) != (-1)))
{
//char s[256];
//sprintf(s,"SetFilePointer(0x%X)",hFile);
//OutputDebugString(s);
if(dwMoveMethod == FILE_BEGIN) {
OpenArchRecords[iArch].dwReadPosition = lDistanceToMove;
OpenArchRecords[iArch].pbyteDataCurrent = OpenArchRecords[iArch].pbyteDataStart + lDistanceToMove;
}
else if(dwMoveMethod == FILE_CURRENT) {
OpenArchRecords[iArch].dwReadPosition += lDistanceToMove;
OpenArchRecords[iArch].pbyteDataCurrent += lDistanceToMove;
}
else if(dwMoveMethod == FILE_END) {
OpenArchRecords[iArch].dwReadPosition = OpenArchRecords[iArch].dwFileSize;
OpenArchRecords[iArch].pbyteDataCurrent =
OpenArchRecords[iArch].pbyteDataStart + OpenArchRecords[iArch].dwFileSize;
}
return OpenArchRecords[iArch].dwReadPosition;
}
return Real_SetFilePointer(hFile,lDistanceToMove,lpDistanceToMoveHigh,dwMoveMethod);
}
@ -82,7 +294,14 @@ DWORD WINAPI Arch_SetFilePointer( HANDLE hFile,LONG lDistanceToMove,
BOOL WINAPI Arch_CloseHandle( HANDLE hObject )
{
// TODO: Arch_CloseHandle
int iArch;
if( IsCustomFileHandle((DWORD)hObject) &&
((iArch = FindArchRecordIndexFromHandle(hObject)) != (-1)))
{
bArchRecordSlotState[iArch] = FALSE;
return TRUE;
}
return Real_CloseHandle(hObject);
}
@ -91,7 +310,13 @@ BOOL WINAPI Arch_CloseHandle( HANDLE hObject )
DWORD WINAPI Arch_GetFileType( HANDLE hFile )
{
// TODO: Arch_GetFileType
int iArch;
if( IsCustomFileHandle((DWORD)hFile) &&
((iArch = FindArchRecordIndexFromHandle(hFile)) != (-1)))
{
return FILE_TYPE_DISK;
}
return Real_GetFileType(hFile);
}
@ -174,3 +399,92 @@ void UninstallFileSystemHooks()
//----------------------------------------------------------
char * FileNameOnly(char *sz)
{
// remove the trailing space, if it's there.
if(sz[strlen(sz) - 1] == ' ') {
sz[strlen(sz) - 1] = '\0';
}
char * org = sz;
char * search = sz + strlen(sz);
while(search != org) {
if(*search == '/' || *search == '\\') {
return (search+1);
}
search--;
}
return org;
}
//----------------------------------------------------------
char * ExtensionOnly(char *sz)
{
// remove the trailing space, if it's there.
if(sz[strlen(sz) - 1] == ' ') {
sz[strlen(sz) - 1] = '\0';
}
char * org = sz;
char * search = sz + strlen(sz);
while(search != org) {
if(*search == '.') {
return (search+1);
}
search--;
}
return org;
}
//----------------------------------------------------------
char* strtolower(char* sz)
{
char* ret = sz;
while (*sz)
{
*sz = tolower(*sz);
sz++;
}
return ret;
}
//----------------------------------------------------------
void CheckFileNameHash(UINT *pDigest)
{
if( pDigest[0] == dwHandlingDigest[0] &&
pDigest[1] == dwHandlingDigest[1] &&
pDigest[2] == dwHandlingDigest[2] &&
pDigest[3] == dwHandlingDigest[3] &&
pDigest[4] == dwHandlingDigest[4] )
{
if(pGame)
pGame->sub_10062570();
}
if( pDigest[0] == dwWeaponDigest[0] &&
pDigest[1] == dwWeaponDigest[1] &&
pDigest[2] == dwWeaponDigest[2] &&
pDigest[3] == dwWeaponDigest[3] &&
pDigest[4] == dwWeaponDigest[4] )
{
if(pGame)
pGame->sub_10062570();
}
if( pDigest[0] == dwMeleeDigest[0] &&
pDigest[1] == dwMeleeDigest[1] &&
pDigest[2] == dwMeleeDigest[2] &&
pDigest[3] == dwMeleeDigest[3] &&
pDigest[4] == dwMeleeDigest[4] )
{
if(pGame)
pGame->sub_10062570();
}
}
//----------------------------------------------------------

View File

@ -9,10 +9,17 @@ void UninstallFileSystemHooks();
typedef struct _ARCH_FILE_RECORD
{
char _gap0[20];
HANDLE hHandle;
DWORD dwReadPosition;
DWORD dwFileSize;
BYTE * pbyteDataStart;
BYTE * pbyteDataCurrent;
} ARCH_FILE_RECORD;
#define CUSTOM_HANDLE_BASE 0xFF000001
#define CUSTOM_HANDLE_LIMIT 0xFF000101
// File API definitions
typedef DWORD (WINAPI *def_GetFileSize)(HANDLE,PDWORD);
typedef DWORD (WINAPI *def_SetFilePointer)(HANDLE,LONG,PLONG,DWORD);

View File

@ -85,6 +85,8 @@ public:
//-----------------------------------------------------------
void sub_10062570() { field_55++; };
CPlayerPed *FindPlayerPed() {
if(m_pGamePlayer==NULL) m_pGamePlayer = new CPlayerPed();
return m_pGamePlayer;