|
|
#include <ntos.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntosdef.h>
#include <ntioapi.h>
#include <ntstatus.h>
#include <stdlib.h>
#include <windef.h>
#include "patchapi.h"
#include "const.h"
VOID NtGetParameter(IN INT iTh, IN WCHAR* strLine, OUT WCHAR* strParam, IN WCHAR cLimit); BOOL NtIsUnicodeFile(IN HANDLE hFile); BOOL NtReadLine(IN HANDLE hFile, OUT WCHAR* strLine); BOOL NtCopyThisFile(IN WCHAR* strFrom, IN WCHAR* strTo, IN BOOL blnDeleteFrom); BOOL NtPatchFile(IN WCHAR* strOldFile, IN WCHAR* strPatchFile, IN WCHAR* strNewFile); BOOL NtCreateZeroFile(IN WCHAR* strFile); BOOL NtCreateThisDirectory(IN WCHAR* strDirectory, IN WCHAR* strAttrib); BOOL NtDeleteThisDirectory(IN WCHAR* strDirectory);
///////////////////////////////////////////////////////////////////////////////
//
// main, the entry point for the OEMApply tool, it opens up the script file and
// read it line by line. Each line tells the tool what to do.
//
// Parameters:
//
// none
//
// Return:
//
// none
//
///////////////////////////////////////////////////////////////////////////////
extern "C" VOID __cdecl main(VOID) { OBJECT_ATTRIBUTES myFileObject; HANDLE hScriptFile = NULL; IO_STATUS_BLOCK statusScriptFile; UNICODE_STRING strScriptFile;
// initialize the filename and so on
strScriptFile.Length = wcslen(APPLY_PATCH_SCRIPT) + 1; strScriptFile.MaximumLength = strScriptFile.Length; strScriptFile.Buffer = (USHORT*)APPLY_PATCH_SCRIPT;
InitializeObjectAttributes(&myFileObject, &strScriptFile, OBJ_EXCLUSIVE, NULL, NULL);
// open the script file, remove the file when we are done
if(NtCreateFile(&hScriptFile, FILE_READ_DATA | DELETE | SYNCHRONIZE, &myFileObject, &statusScriptFile, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0) == STATUS_SUCCESS) { // script file should be to be unicoded
if(NtIsUnicodeFile(hScriptFile)) { // local varibles
BOOL blnReturn = TRUE; WCHAR strThisLine[SUPER_LENGTH / 2]; WCHAR strAction[LANGUAGE_LENGTH]; WCHAR strParam1[STRING_LENGTH]; WCHAR strParam2[STRING_LENGTH]; WCHAR strParam3[STRING_LENGTH];
// get a line from the script file in strThisLine, strThisLine is
// NULL terminated with no end of line or carriage return
while(NtReadLine(hScriptFile, strThisLine)) { blnReturn = TRUE; // get the first token from strThisLine, strThisLine is
// not changed by NtGetParameter, all filenames are of
// full path
NtGetParameter(1, strThisLine, strAction, SEPARATOR[0]); switch(strAction[0]) { case ACTION_C_NEW_DIRECTORY: // get directory name
NtGetParameter(2, strThisLine, strParam1, SEPARATOR[0]); // get directory attributes, can be NULL
NtGetParameter(3, strThisLine, strParam2, SEPARATOR[0]); blnReturn = NtCreateThisDirectory(strParam1, strParam2); break; case ACTION_C_PATCH_FILE: // get the old filename
NtGetParameter(2, strThisLine, strParam1, SEPARATOR[0]); // get the patch filename
NtGetParameter(3, strThisLine, strParam2, SEPARATOR[0]); // get the new filename
NtGetParameter(4, strThisLine, strParam3, SEPARATOR[0]); blnReturn = NtPatchFile(strParam1, strParam2, strParam3); break; case ACTION_C_MOVE_FILE: case ACTION_C_EXCEPT_FILE: case ACTION_C_RENAME_FILE: case ACTION_C_NOT_PATCH_FILE: case ACTION_C_SAVED_FILE: // get the old filename
NtGetParameter(2, strThisLine, strParam1, SEPARATOR[0]); // get the new filename
NtGetParameter(3, strThisLine, strParam2, SEPARATOR[0]); // delete the old file once we are done
blnReturn = NtCopyThisFile(strParam1, strParam2, TRUE); break; case ACTION_C_COPY_FILE: // get the old filename
NtGetParameter(2, strThisLine, strParam1, SEPARATOR[0]); // get the new filename
NtGetParameter(3, strThisLine, strParam2, SEPARATOR[0]); // do not remove the old file
blnReturn = NtCopyThisFile(strParam1, strParam2, FALSE); break; case ACTION_C_NEW_ZERO_FILE: // get the filename
NtGetParameter(2, strThisLine, strParam1, SEPARATOR[0]); blnReturn = NtCreateZeroFile(strParam1); break; case ACTION_C_DELETE_DIRECTORY: // get the directory name
NtGetParameter(2, strThisLine, strParam1, SEPARATOR[0]); blnReturn = NtDeleteThisDirectory(strParam1); break; default: break; } if(!blnReturn) { // some thing went wrong
DbgPrint("warning, A=%ls, 1=%ls, 2=%ls, 3=%ls\n", strAction, strParam1, strParam2, strParam3); } } } NtClose(hScriptFile); } }
///////////////////////////////////////////////////////////////////////////////
//
// NtGetParameter, essentially a wcstok function, returns the iTh token
// separated by cLimit in strParam, if the token is not found,
// strParam is of 0 length, strLine is unchanged
//
// Parameters:
//
// iTh, the nTh token
// strLine, the line of characters that the token is taken from
// strParam, the returned token
// cLimit, the character the separates the tokens
//
// Return:
//
// none
//
///////////////////////////////////////////////////////////////////////////////
VOID NtGetParameter(IN INT iTh, IN WCHAR* strLine, OUT WCHAR* strParam, IN WCHAR cLimit) { INT iCount = 0; INT iPrevCount = 0; INT iEncounter = 0; INT iLength = 0;
if(iTh > 0 && strLine && strParam) { while(strLine[iCount] != 0) { if(strLine[iCount] == cLimit) { // just like the real wcstok, ignores the first token separator
if(iCount != 0) { iEncounter += 1; } if(iEncounter == iTh) { break; } iPrevCount = iCount + 1; } iCount += 1; } // two conditions for successful return
// 1. the token is found
// 2. reached the end of line, and this is the token we want
if(iEncounter == iTh || iEncounter + 1 == iTh) { iLength = iCount - iPrevCount; wcsncpy(strParam, strLine + iPrevCount, iLength); strParam[iLength] = 0; } else { // zero out the return token if token is not found
strParam[0] = 0; } } }
///////////////////////////////////////////////////////////////////////////////
//
// NtIsUnicodeFile, test to see if the file is unicoded by reading the first 2
// bytes, should be FEFF, the file position is moved for next
// read
//
// Parameters:
//
// hFile, the file handle to read from
//
// Return:
//
// TRUE if the first 2 bytes matches, FALSE otherwise
//
///////////////////////////////////////////////////////////////////////////////
BOOL NtIsUnicodeFile(IN HANDLE hFile) { WCHAR cFirstChar = 0; IO_STATUS_BLOCK ioBlock;
// read the first 2 bytes
if(NtReadFile(hFile, NULL, NULL, NULL, &ioBlock, &cFirstChar, sizeof(WCHAR), NULL, NULL) && cFirstChar == UNICODE_HEAD) { return(TRUE); }
return(FALSE); }
///////////////////////////////////////////////////////////////////////////////
//
// NtReadLine, reads a line from hFile, each line in hFile is expected to be
// terminated by 0xD and 0xA, the line will be returned in strLine,
// with 0xD and 0xA removed
//
// Parameters:
//
// hFile, the file handle to read from
// strLine, the buffer to store the line
//
// Return:
//
// TRUE if the strLine contains a valid line, FALSE for end of file
//
///////////////////////////////////////////////////////////////////////////////
BOOL NtReadLine(IN HANDLE hFile, OUT WCHAR* strLine) { static WCHAR strBuffer[SUPER_LENGTH + 1]; static LONG iLength = 0; static LONG iReadChar = 0; static LONG iOffset = 0; static LONG iThisLineLength = 0; static WCHAR strThisLine[SUPER_LENGTH / 2]; static IO_STATUS_BLOCK ioBlock;
if(iLength > 0) { NtGetParameter(1, strBuffer + iReadChar - iLength, strThisLine, CRETURN[0]); iThisLineLength = wcslen(strThisLine); if(iThisLineLength + 1 <= iLength) { // char 0xD is set to 0
strThisLine[iThisLineLength - 1] = 0; wcscpy(strLine, strThisLine); iLength = iLength - iThisLineLength - 1; } else { wcsncpy(strLine, strThisLine, iLength); // set the last char + 1 to 0 for cat
strLine[iLength] = 0; if(iLength <= 0 || strLine[iLength - 1] != ENDOFLINE[0]) { NtReadFile(hFile, NULL, NULL, NULL, &ioBlock, strBuffer, SUPER_LENGTH * sizeof(WCHAR), NULL, NULL); iReadChar = ioBlock.Information / sizeof(WCHAR); NtGetParameter(1, strBuffer, strThisLine, CRETURN[0]); iThisLineLength = wcslen(strThisLine); iLength = iReadChar - iThisLineLength - 1; // char 0xD is set to 0
strThisLine[iThisLineLength - 1] = 0; wcscat(strLine, strThisLine); if(strBuffer[0] == CRETURN[0]) { iLength -= 1; } } else { strLine[iLength - 1] = 0; iLength = 0; } } } else { if(NtReadFile(hFile, NULL, NULL, NULL, &ioBlock, strBuffer, SUPER_LENGTH * sizeof(WCHAR), NULL, NULL) == STATUS_SUCCESS && ioBlock.Information != 0) { iReadChar = ioBlock.Information / sizeof(WCHAR); NtGetParameter(1, strBuffer, strThisLine, CRETURN[0]); iThisLineLength = wcslen(strThisLine); iLength = iReadChar - iThisLineLength - 1; // char 0xD is set to 0
strThisLine[iThisLineLength - 1] = 0; wcscpy(strLine, strThisLine); if(strBuffer[0] == CRETURN[0]) { iLength -= 1; } } else { return(FALSE); } }
return(TRUE); }
///////////////////////////////////////////////////////////////////////////////
//
// NtCopyThisFile, copies a file to another location, depending on
// blnDeleteFrom, the old file can be deleted
//
// Parameters:
//
// strFrom, the old filename, full path
// strTo, the new filename, full path
// blnDeleteFrom, delete the old file?
//
// Return:
//
// TRUE for file copied successfully, FALSE otherwise
//
///////////////////////////////////////////////////////////////////////////////
BOOL NtCopyThisFile(IN WCHAR* strFrom, IN WCHAR* strTo, IN BOOL blnDeleteFrom) { BOOL blnReturn = FALSE; BYTE byteBuffer[1024]; ULONG iCreateOptions = 0; ULONG iDesireAccess = 0;
// set the options to delete the old file
if(blnDeleteFrom) { iCreateOptions = FILE_DELETE_ON_CLOSE; iDesireAccess = DELETE; }
OBJECT_ATTRIBUTES myFileReadObject; OBJECT_ATTRIBUTES myFileWriteObject;
HANDLE hReadFile = NULL; HANDLE hWriteFile = NULL;
IO_STATUS_BLOCK statusReadFile; IO_STATUS_BLOCK statusWriteFile;
UNICODE_STRING strReadFile; UNICODE_STRING strWriteFile;
IO_STATUS_BLOCK statusReadInfoFile; FILE_BASIC_INFORMATION infoReadFile; IO_STATUS_BLOCK ioReadBlock; IO_STATUS_BLOCK ioWriteBlock;
strReadFile.Length = wcslen(strFrom) + 1; strReadFile.MaximumLength = strReadFile.Length; strReadFile.Buffer = strFrom;
strReadFile.Length = wcslen(strTo) + 1; strReadFile.MaximumLength = strReadFile.Length; strReadFile.Buffer = strTo;
InitializeObjectAttributes(&myFileReadObject, &strReadFile, OBJ_EXCLUSIVE, NULL, NULL);
InitializeObjectAttributes(&myFileWriteObject, &strWriteFile, OBJ_EXCLUSIVE, NULL, NULL);
// open the old file to read
if(NtCreateFile(&hReadFile, FILE_READ_DATA | SYNCHRONIZE | FILE_READ_ATTRIBUTES | iDesireAccess, &myFileReadObject, &statusReadFile, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | iCreateOptions, NULL, 0) == STATUS_SUCCESS) { // get the old file's attributes
if(NtQueryInformationFile(hReadFile, &statusReadInfoFile, &infoReadFile, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation) == STATUS_SUCCESS) { // create the new file with old file's attributes
if(NtCreateFile(&hWriteFile, FILE_WRITE_DATA | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, &myFileWriteObject, &statusWriteFile, NULL, infoReadFile.FileAttributes, 0, FILE_CREATE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0) == STATUS_SUCCESS) { blnReturn = TRUE; // read from the old file and write to the new file
while(NtReadFile(hReadFile, NULL, NULL, NULL, &ioReadBlock, byteBuffer, 1024, NULL, NULL) == STATUS_SUCCESS && ioReadBlock.Information != 0 && blnReturn) { // make sure that write is successful
blnReturn = (NtWriteFile(hWriteFile, NULL, NULL, NULL, &ioWriteBlock, byteBuffer, ioReadBlock.Information, NULL, NULL) == STATUS_SUCCESS && ioWriteBlock.Information == ioReadBlock.Information); } NtClose(hWriteFile); } } NtClose(hReadFile); }
return(blnReturn); }
///////////////////////////////////////////////////////////////////////////////
//
// NtCreateZeroFile, creates a zero length file
//
// Parameters:
//
// strFile, the filename, full path
//
// Return:
//
// TRUE for file created successfully, FALSE otherwise
//
///////////////////////////////////////////////////////////////////////////////
BOOL NtCreateZeroFile(IN WCHAR* strFile) { BOOL blnReturn = FALSE; HANDLE hFile = NULL;
OBJECT_ATTRIBUTES myFileObject; IO_STATUS_BLOCK statusFile; UNICODE_STRING strUniFile;
strUniFile.Length = wcslen(strFile) + 1; strUniFile.MaximumLength = strUniFile.Length; strUniFile.Buffer = strFile;
InitializeObjectAttributes(&myFileObject, &strUniFile, OBJ_EXCLUSIVE, NULL, NULL);
if(NtCreateFile(&hFile, FILE_WRITE_DATA | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, &myFileObject, &statusFile, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0) == STATUS_SUCCESS) { blnReturn = TRUE; NtClose(hFile); }
return(blnReturn); }
///////////////////////////////////////////////////////////////////////////////
//
// NtPatchFile, create the new file from the patch file
//
// Parameters:
//
// strOldFile, the old filename, full path
// strPatchFile, the patch filename, full path
// strNewFile, the new filename, full path
//
// Return:
//
// TRUE for file created successfully, FALSE otherwise
//
///////////////////////////////////////////////////////////////////////////////
BOOL NtPatchFile(IN WCHAR* strOldFile, IN WCHAR* strPatchFile, IN WCHAR* strNewFile) { BOOL blnReturn = TRUE;
blnReturn = ApplyPatchToFileW(strPatchFile, strOldFile, strNewFile, 0);
return(blnReturn); }
///////////////////////////////////////////////////////////////////////////////
//
// NtCreateThisDirectory, create a directory
//
// Parameters:
//
// strDirectory, the name of the directory, full path
// strAttrib, the attributes of the directory
//
// Return:
//
// TRUE for directory created successfully, FALSE otherwise
//
///////////////////////////////////////////////////////////////////////////////
BOOL NtCreateThisDirectory(IN WCHAR* strDirectory, IN WCHAR* strAttrib) { BOOL blnReturn = FALSE; HANDLE hDirectory = NULL;
OBJECT_ATTRIBUTES myDirectoryObject; IO_STATUS_BLOCK statusDirectory; UNICODE_STRING strUniDirectory;
strUniDirectory.Length = wcslen(strDirectory) + 1; strUniDirectory.MaximumLength = strUniDirectory.Length; strUniDirectory.Buffer = strDirectory;
InitializeObjectAttributes(&myDirectoryObject, &strUniDirectory, OBJ_EXCLUSIVE, NULL, NULL);
// create the directory
if(NtCreateFile(&hDirectory, FILE_WRITE_DATA | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, &myDirectoryObject, &statusDirectory, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE, FILE_DIRECTORY_FILE, NULL, 0) == STATUS_SUCCESS) { blnReturn = TRUE; }
if(blnReturn) { DWORD iAttrib = FILE_ATTRIBUTE_NORMAL; LARGE_INTEGER iLargeInt; FILE_BASIC_INFORMATION infoDirectory;
// look through the attributes
for(UINT i = 0; i < wcslen(strAttrib); i++) { switch(strAttrib[i]) { case DIR_C_READONLY: iAttrib |= FILE_ATTRIBUTE_READONLY; break; case DIR_C_SYSTEM: iAttrib |= FILE_ATTRIBUTE_SYSTEM; break; case DIR_C_HIDDEN: iAttrib |= FILE_ATTRIBUTE_HIDDEN; break; case DIR_C_COMPRESSED: iAttrib |= FILE_ATTRIBUTE_COMPRESSED; break; case DIR_C_ENCRYPTED: iAttrib |= FILE_ATTRIBUTE_ENCRYPTED; break; default: break; } } NtQuerySystemTime(&iLargeInt); // set the information struct
infoDirectory.CreationTime = iLargeInt; infoDirectory.LastAccessTime = iLargeInt; infoDirectory.LastWriteTime = iLargeInt; infoDirectory.ChangeTime = iLargeInt; infoDirectory.FileAttributes = iAttrib;
// set the attributes
blnReturn = (NtSetInformationFile(hDirectory, &statusDirectory, &infoDirectory, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation) == STATUS_SUCCESS);
NtClose(hDirectory); }
return(blnReturn); }
///////////////////////////////////////////////////////////////////////////////
//
// NtDeleteThisDirectory, deletes the directory recursively
//
// Parameters:
//
// strDirectory, the name of the directory, full path
// strAttrib, the attributes of the directory
//
// Return:
//
// TRUE for directory removed, FALSE otherwise
//
///////////////////////////////////////////////////////////////////////////////
BOOL NtDeleteThisDirectory(IN WCHAR* strDirectory) { INT length = 0; NTSTATUS result; WCHAR path[MAXPATH + 7];
HANDLE hVddHeap = NULL;
HANDLE hFindFile = NULL; OBJECT_ATTRIBUTES myFileObject; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING strUniFile;
PFILE_BOTH_DIR_INFORMATION DirectoryInfo = NULL;
// adding the trailing '\'
if((length = wcslen(strDirectory)) > MAXPATH) { return FALSE; } wcscpy(path, strDirectory);
if(length) { if((path[length - 1] != '\\') AND (path[length - 1] != ':')) { wcscpy(path + length, L"\\"); length++; } }
strUniFile.Length = length; strUniFile.MaximumLength = strUniFile.Length; strUniFile.Buffer = strDirectory;
InitializeObjectAttributes(&myFileObject, &strUniFile, OBJ_EXCLUSIVE, NULL, NULL);
// allocate memory for the directory info struct used to get files from
// the directory
DirectoryInfo = (PFILE_BOTH_DIR_INFORMATION)RtlAllocateHeap( RtlProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) + sizeof(FILE_BOTH_DIR_INFORMATION));
// open the directory
if(DirectoryInfo != NULL && NtCreateFile(&hFindFile, FILE_LIST_DIRECTORY | SYNCHRONIZE | DELETE, &myFileObject, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE, NULL, 0) == STATUS_SUCCESS) { // get a file
result = NtQueryDirectoryFile(hFindFile, NULL, NULL, NULL, &IoStatusBlock, DirectoryInfo, (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_BOTH_DIR_INFORMATION)), FileBothDirectoryInformation, TRUE, NULL, TRUE);
while(result == STATUS_SUCCESS) { ULONG iLengthFull = DirectoryInfo->FileNameLength / sizeof(WCHAR); DirectoryInfo->FileName[iLengthFull] = 0; if((DirectoryInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY && wcscmp(DirectoryInfo->ShortName, L"." ) != 0 && wcscmp(DirectoryInfo->ShortName, L"..") != 0) { // the file is a directory
NtDeleteThisDirectory(DirectoryInfo->FileName); } else { // the file is a file
HANDLE hFindFileFile = NULL; OBJECT_ATTRIBUTES myFileFileObject; IO_STATUS_BLOCK FileIoStatusBlock; UNICODE_STRING strUniFileFile;
strUniFileFile.Length = (USHORT)iLengthFull; strUniFileFile.MaximumLength = strUniFile.Length; strUniFileFile.Buffer = DirectoryInfo->FileName;
InitializeObjectAttributes(&myFileFileObject, &strUniFileFile, OBJ_EXCLUSIVE, NULL, NULL);
if(NtCreateFile(&hFindFileFile, SYNCHRONIZE | DELETE, &myFileFileObject, &FileIoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE, NULL, 0) == STATUS_SUCCESS) { NtClose(hFindFileFile); } }
result = NtQueryDirectoryFile(hFindFile, NULL, NULL, NULL, &IoStatusBlock, DirectoryInfo, (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_BOTH_DIR_INFORMATION)), FileBothDirectoryInformation, TRUE, NULL, FALSE); } }
if(DirectoryInfo != NULL) { // free the memory
RtlFreeHeap(RtlProcessHeap(), 0, DirectoryInfo); DirectoryInfo = NULL; }
// close the handle to the directory, since the directory is opened with
// the delete on close option, the directory should be deleted
return(NtClose(hFindFile) == STATUS_SUCCESS); }
|