Unusual characters while printing after using ReadFile - c

I have a simple text file that has "SakyLabs. Hello, MDE", and I am trying to reading it using ReadFile function and then printing out, but I am getting:
?SakyLabs. Hello, MDE??²
What am I doing wrong?
Here's the code:
// For CreateFileW
HANDLE createFile;
DWORD fileDesiredAccess = GENERIC_READ | GENERIC_WRITE;
DWORD fileShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
DWORD creationDisposition = CREATE_ALWAYS;
DWORD fileFlags = FILE_ATTRIBUTE_NORMAL;
// ReadFile function
BOOL readFile;
DWORD lastError;
DWORD fileSize;
LPWSTR fileBuffer;
DWORD bytesRead;
if ((wcscmp(argv[1], L"-ef") == 0))
{
createFile = CreateFileW(argv[2], fileDesiredAccess, fileShareMode, NULL, OPEN_EXISTING, fileFlags, NULL);
// To get extended error message
lastError = GetLastError();
if (createFile == INVALID_HANDLE_VALUE)
{
wprintf(L"Error %d opening the file: ", lastError);
ShowErrorMessage(lastError);
return;
}
// File was opened! Let's read it's content
fileSize = GetFileSize(createFile, NULL);
fileBuffer = (LPWSTR)malloc((fileSize) + 1);
if (fileBuffer == NULL)
{
wprintf(L"Could not allocated memory.\n");
CloseHandle(createFile);
return;
}
readFile = ReadFile(createFile, fileBuffer, fileSize, &bytesRead, NULL);
lastError = GetLastError();
if (!readFile)
{
wprintf(L"Error code %d reading the file: ", lastError);
ShowErrorMessage(lastError);
CloseHandle(createFile);
return;
}
fileBuffer[fileSize] = '\0';
// Show the content
wprintf(L"%s \n", fileBuffer);
free(fileBuffer);
CloseHandle(createFile);
}
return 0;
}

This line is wrong:
fileBuffer[fileSize] = '\0';
fileSize is expressed in raw bytes, but fileBuffer is an array of WCHAR elements, where WCHAR is 2 bytes in size. As such, you end up writing way past the end of the array into surrounding memory, which is undefined behavior.
Put another way, your file is 40 bytes in size, and you are allocating 40+1 bytes for your array. That array can hold a max of 20 WCHARs, which means its valid indexes are 0..19, but since you are using fileSize as an index, you are writing the '\0' to the WCHAR located at index 40.
To fix that, you need to change this:
fileBuffer = (LPWSTR)malloc((fileSize) + 1);
...
fileBuffer[fileSize] = '\0';
To this instead:
fileBuffer = (LPWSTR)malloc(fileSize + sizeof(WCHAR));
...
fileBuffer[fileSize / sizeof(WCHAR)] = L'\0';
Now it will write the L'\0' into index 20, which is the array element that +sizeof(WCHAR) is allocating space for.
Alternatively, you don't have to null-terminate the array at all, if you instead tell wprintf() how many WCHARs to print, eg:
wprintf(L"%.*s \n", (int)(fileSize / sizeof(WCHAR)), fileBuffer);
On a side note -
Your code is not checking if GetFileSize() failed before using fileSize.
Also, when calling ReadFile(), fileSize is the requested number of bytes to read, but bytesRead receives the number of bytes actually read. ReadFile() can return fewer bytes than requested. So, you should use bytesRead instead of fileSize when terminating/printing fileBuffer. Otherwise, call ReadFile() in a loop to ensure all of the required bytes are actually read.
And, you are leaking fileBuffer if ReadFile() fails.

1.You should initialize the buffer fileBuffer.
2.fileBuffer size should be fileSize+2.
3.FF FE is the leading BOM.
If the 16-bit units use little-endian order ("UTF-16LE"), the BOM is
the (hexadecimal) byte sequence FF FE
Update the revised code:
#include<windows.h>
#include<wchar.h>
int main()
{
// For CreateFileW
HANDLE createFile;
DWORD fileDesiredAccess = GENERIC_READ | GENERIC_WRITE;
DWORD fileShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
DWORD creationDisposition = CREATE_ALWAYS;
DWORD fileFlags = FILE_ATTRIBUTE_NORMAL;
// ReadFile function
BOOL readFile;
DWORD lastError;
DWORD fileSize;
LPWSTR fileBuffer;
DWORD bytesRead;
{
createFile = CreateFileW(L"Test.txt", fileDesiredAccess, fileShareMode, NULL, OPEN_EXISTING, fileFlags, NULL);
// To get extended error message
lastError = GetLastError();
if (createFile == INVALID_HANDLE_VALUE)
{
wprintf(L"Error %d opening the file: ", lastError);
return 0;
}
// File was opened! Let's read it's content
fileSize = GetFileSize(createFile, NULL);
fileBuffer = (LPWSTR)malloc((fileSize)+2);
if (fileBuffer == NULL)
{
wprintf(L"Could not allocated memory.\n");
CloseHandle(createFile);
return 0;
}
else
{
memset(fileBuffer,0, (fileSize)+2);
}
readFile = ReadFile(createFile, fileBuffer, fileSize, &bytesRead, NULL);
lastError = GetLastError();
if (!readFile)
{
wprintf(L"Error code %d reading the file: ", lastError);
CloseHandle(createFile);
return 0;
}
//fileBuffer[fileSize] = '\0';
// Show the content
wprintf(L"%s \n", fileBuffer+1);
free(fileBuffer);
CloseHandle(createFile);
}
return 0;
}

Related

What is wrong with this simple code meant to decrypt with AES 256 bit key using the Windows CryptoAPI?

I have a small program that is encrypting files using the AES-256 key. The key used to encrypt the file is generated randomly.
The encryption program goes like this:
Acquire crypto context - CryptAcquireContext
generate an AES-256 key using CryptGenKey
Encrypt a file using this key -- CryptEncrypt
Release cryto context -- CryptReleaseContext
The file encrypted is a small test.txt file containing the string: "just a test". And so the raw hex bytes in the file are:
6A 75 73 74 20 61 20 74 65 73 74
The AES-256 key used for encryption in hex format is:
3f10e23bb1a5dfd9c8ca06195e43043386a9ba4c63c35ac518f463ba768f001b
The encrypted file test.enc then has the bytes:
C8 B5 92 51 22 53 75 A1 34 80 EC AA 37 1C 6C BE
Question:
How do I write a c/c++ program to decrypt these bytes using the hex AES-256 key using the Windows CryptoAPI's CryptDecrypt function?
What I have tried:
I have written the following decryption program (a slight modification of the gist here.)
#include <Windows.h>
#include <wincrypt.h>
#include <stdio.h>
#pragma comment(lib, "crypt32.lib")
#define BLOCK_LEN 128
HCRYPTPROV hCryptProv;
int wmain(int argc, wchar_t* argv[])
{
wchar_t default_key[] = L"PxDiO7Gl39nIygYZXkMEM4apukxjw1rFGPRjunaPABs";
wchar_t* key_str = default_key;
size_t len = lstrlenW(key_str);
if (!CryptAcquireContext(
&hCryptProv,
NULL,
MS_ENH_RSA_AES_PROV,
PROV_RSA_AES,
NULL))
{
/*std::cout << "error acquiring context\n";
std::cout << GetLastErrorAsString();*/
exit(1);
}
HCRYPTKEY hKey;
wchar_t* filename = argv[1];
wchar_t* filename2 = argv[2];
printf("Key: %S\n", key_str);
printf("Key len: %#x\n", len);
printf("Input File: %S\n", filename);
printf("Output File: %S\n", filename2);
printf("----\n");
HANDLE hInpFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hInpFile == INVALID_HANDLE_VALUE) {
printf("Cannot open input file!\n");
system("pause");
return (-1);
}
printf("\nEncrypted file read.");
HANDLE hOutFile = CreateFileW(filename2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hOutFile == INVALID_HANDLE_VALUE) {
printf("Cannot open output file!\n");
system("pause");
return (-1);
}
printf("\nDecryption file created.");
DWORD dwStatus = 0;
BOOL bResult = FALSE;
wchar_t info[] = L"Microsoft Enhanced RSA and AES Cryptographic Provider";
/*BOOL CryptDeriveKey(
HCRYPTPROV hProv,
ALG_ID Algid,
HCRYPTHASH hBaseData,
DWORD dwFlags,
HCRYPTKEY * phKey
);*/
HCRYPTHASH hHash;
if (!CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hHash)) {
dwStatus = GetLastError();
printf("CryptCreateHash failed: %x\n", dwStatus);
CryptReleaseContext(hCryptProv, 0);
system("pause");
return dwStatus;
}
if (!CryptHashData(hHash, (BYTE*)key_str, len, 0)) {
DWORD err = GetLastError();
printf("CryptHashData Failed : %#x\n", err);
system("pause");
return (-1);
}
printf("[+] CryptHashData Success\n");
if (!CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey)) {
dwStatus = GetLastError();
printf("CryptDeriveKey failed: %x\n", dwStatus);
CryptReleaseContext(hCryptProv, 0);
system("pause");
return dwStatus;
}
printf("[+] CryptDeriveKey Success\n");
const size_t chunk_size = BLOCK_LEN;
BYTE chunk[chunk_size] = { 0 };
DWORD out_len = 0;
BOOL isFinal = FALSE;
DWORD readTotalSize = 0;
DWORD inputSize = GetFileSize(hInpFile, NULL);
while (bResult = ReadFile(hInpFile, chunk, chunk_size, &out_len, NULL)) {
if (0 == out_len) {
break;
}
printf("\nFile read.");
readTotalSize += out_len;
if (readTotalSize == inputSize) {
isFinal = TRUE;
printf("\nFinal chunk set.\n");
}
printf("\n Now calling decryption routine...");
if (!CryptDecrypt(hKey, NULL, isFinal, 0, chunk, &out_len)) {
printf("[-] CryptDecrypt failed\n");
break;
}
printf("CryptDecrypt succeeded.");
DWORD written = 0;
if (!WriteFile(hOutFile, chunk, out_len, &written, NULL)) {
printf("writing failed!\n");
break;
}
memset(chunk, 0, chunk_size);
}
CryptReleaseContext(hCryptProv, 0);
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CloseHandle(hInpFile);
CloseHandle(hOutFile);
printf("Finished. Processed %#x bytes.\n", readTotalSize);
system("pause");
return 0;
}
This just ends up telling me CryptDecrypt failed. So I'm guessing the key wasn't specified in the right format. I do not know how to use my AES-256 key in hex format to decrypt the data. The key is currently hard-coded in a base64 format in the program but I'm guessing that's not correct.
Another thing I have done is that I have used the CryptoTester tool to specify the AES key that I have in hex format and it is able to actually successfully decrypt the file. Also, this online decryption tool is also able to use the key to decrypt the data as shown here. So I know that I have the right hex key and everything and that the file can decrypted, but how do I rewrite my program above to correctly decrypt the file?
Note that all keys used or shown here are just examples.
How do I correct this program to actually decrypt the data successfully using the AES-256 key above?
Simple Demo Program
Here is a small C program that uses your key and the encrypted data supplied with it and decrypts the original text again. I have tried to make it minimalistic.
For the sake of simplicity, it does not read the files from the file system, but defines the data in the C program as hex strings.
Result
When you run the program, the following output is output to the console:
decrypted result: 'just a test'
C Code
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
void error(const char* what) {
fprintf(stderr, "%s failed with last error 0x%x\n", what, GetLastError());
exit(1);
}
#define AES_KEY_SIZE 32
typedef struct {
BLOBHEADER hdr;
DWORD dwKeySize;
BYTE rgbKeyData[AES_KEY_SIZE];
} AES256KEYBLOB;
BYTE *hex2byte(const char *hex) {
int len = strlen(hex) / 2;
BYTE* bytes = malloc(len);
if (bytes == NULL) {
error("malloc");
return NULL;
}
unsigned char val[2];
for (int i = 0; i < len; i++) {
sscanf_s(&hex[i * 2], "%2hhx", &val);
bytes[i] = val[0];
}
return bytes;
}
int main() {
BYTE *key = hex2byte("3F10E23BB1A5DFD9C8CA06195E43043386A9BA4C63C35AC518F463BA768F001B");
AES256KEYBLOB aes256KeyBlob;
aes256KeyBlob.hdr.bType = PLAINTEXTKEYBLOB;
aes256KeyBlob.hdr.bVersion = CUR_BLOB_VERSION;
aes256KeyBlob.hdr.reserved = 0;
aes256KeyBlob.hdr.aiKeyAlg = CALG_AES_256;
aes256KeyBlob.dwKeySize = AES_KEY_SIZE;
memcpy(aes256KeyBlob.rgbKeyData, key, AES_KEY_SIZE);
HCRYPTPROV hProv;
if (!CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV_A, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
error("CryptAcquireContext");
}
HCRYPTKEY hKey;
if (!CryptImportKey(hProv, (BYTE*)& aes256KeyBlob, sizeof(AES256KEYBLOB), 0, CRYPT_EXPORTABLE, &hKey)) {
CryptReleaseContext(hProv, 0);
error("CryptImportKey");
}
const char *encodedHex = "C8B59251225375A13480ECAA371C6CBE";
DWORD numBytes = strlen(encodedHex) / 2;
BYTE *encoded = hex2byte(encodedHex);
if (CryptDecrypt(hKey, 0, TRUE, 0, encoded, &numBytes)) {
printf("decrypted result: '");
for (DWORD i = 0; i < numBytes; i++) {
printf("%c", encoded[i]);
}
printf("'\n");
} else {
CryptDestroyKey(hKey);
CryptReleaseContext(hProv, 0);
error("CryptDecrypt");
}
free(key);
free(encoded);
CryptDestroyKey(hKey);
CryptReleaseContext(hProv, 0);
return 0;
}
Microsoft Docs
The KEYBLOB struct is documented here:
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/jj650836(v%3Dvs.85)
whereas here you will find information about the BLOBHEADER structure:
https://learn.microsoft.com/en-us/windows/desktop/api/wincrypt/ns-wincrypt-publickeystruc

What does it mean for ReadFile to be "completing asynchronously", and why is it an error?

I'm (synchronously) reading serial input in Windows using ReadFile(), but instead of waiting for the serial port to have input then returning that as I thought it should, ReadFile() instead returns immediately with a value of FALSE, and a GetLastError() of 0. (Yes, I'm certain I have the right error code and am not making syscalls in between).
The ReadFile() documentation says that when the function "is completing asynchronously, the return value is zero (FALSE)." How is it that a synchronous read can be completing asychronously? Why would this be an error? It's worth noting that the data read is garbage data, as one might expect.
More generally, how can I force ReadFile() to behave like a simple synchronous read of a serial port, or at least behave something like the UNIX read()?
Edit: Here is some source code:
HANDLE my_connect(char *port_name)
{
DCB dcb;
COMMTIMEOUTS timeouts;
HANDLE hdl = CreateFile(port_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
GetCommState(port_name, &dcb);
dcb.BaudRate = 115200;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
if(SetCommState(hdl, &dcb) == 0)
{
fprintf(stderr, "SetCommState failed with error code %d.\n",
GetLastError());
return (HANDLE) -1;
}
/* TODO: Set a variable timeout. */
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 5000; /* wait 5s for input */
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 5000;
if(SetCommTimeouts(hdl, &timeouts) == 0)
{
fprintf(stderr, "SetCommTimeouts failed with error code %d.\n",
GetLastError());
return (HANDLE) -1;
}
return hdl;
}
int my_disconnect(HANDLE hdl)
{
return CloseHandle(hdl);
}
int my_send(HANDLE hdl, char *cmd)
{
DWORD nb = 0;
if(WriteFile(hdl, cmd, strlen(cmd), &nb, NULL) == 0)
{
fprintf(stderr, "WriteFile failed with error code %d.\n",
GetLastError());
return -1;
}
return (int) nb;
}
int my_receive(HANDLE hdl, char *dst, int dstlen)
{
int i;
DWORD r;
BOOL err;
char c = '\0';
for (i = 0; i < dstlen; err = ReadFile(hdl, &c, 1, &r, NULL))
{
if (err == 0)
{
fprintf(stderr, "ReadFile failed with error code %d.\n",
GetLastError());
return -1;
}
if (r > 0)
{
dst[i++] = c;
if (c == '\n') break;
}
}
if (i == dstlen)
{
fprintf(stderr, "Error: read destination buffer not large enough.\
Recommended size: 256B. Your size: %dB.\n", dstlen);
return -1;
}
else
{
dst[i] = '\0'; /* null-terminate the string. */
}
return i;
}
And my test code:
HANDLE hdl = my_connect("COM4");
char *cmd = "/home\n"; /* basic command */
char reply[256];
my_send(hdl, cmd);
my_receive(hdl, reply, 256);
puts(reply);
It's not completing asynchronously. If it were, GetLastError would return ERROR_IO_PENDING.
To do synchronous I/O, open the file without FILE_FLAG_OVERLAPPED.
It should not be possible for ReadFile to fail without a valid GetLastError code. ReadFile only returns false when the driver sets a non-success status code.

Using ReadFile to read entire PhysicalDrive contents

I am fairly new to C, and I am trying to write a small application that will read the entire raw contents of a drive.
Here is my code;
int main(int argc, char *argv[]) {
HANDLE hFile;
DWORD dwBytesRead;
char buff[512];
hFile = CreateFile("\\\\.\\PhysicalDrive2", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
if(hFile == INVALID_HANDLE_VALUE){
printf("%d",GetLastError());
return;
}
SetFilePointer(hFile, 512*0, NULL, FILE_BEGIN);
ReadFile(hFile, buff, 512, &dwBytesRead, NULL);
CloseHandle(hFile);
return 0;
}
How do I put the ReadFile into a loop to read all the data on the drive? I eventually need to save the contents of the buffer to the disk.
Thanks
The loop might look like this:
hFile = CreateFile(...);
if (hFile == INVALID_HANDLE_VALUE)
{
// handle error
}
while (true)
{
unsigned char buff[32768]; // needs to be a multiple of sector size
DWORD dwBytesRead;
if (!ReadFile(hFile, buff, sizeof buff, &dwBytesRead, NULL))
{
// handle error
}
if (dwBytesRead == 0)
{
break; // we reached the end
}
// do something with the dwBytesRead that were read
}
CloseHandle(hFile);

Can't send wchar_t array through mailslot

I can't send chunks of data bigger than 420 bytes. For example if i try to send 421 bytes, i can't read it with ReadFile. If I check the maislot info with GetMailslotInfo( handleRead, 0, &msgSize, 0, 0 ); then msgSize will always be -1.
So this will never work for me:
err = WriteFile( handleWrite, wcharArrayToSend, 421, &numBytesWritten, NULL );
Does anyone know a reason for this behavior? Is this a normal behavior?
Per MSDN's documentation on mailslots:
The data in a mailslot message can be in any form, but cannot be larger than 424 bytes when sent between computers.
To send messages that are larger than 424 bytes between computers, use named pipes or Windows Sockets instead.
I'm not sure what you've done wrong, but mailslots can definitely handle messages greater than 421 bytes. Here's some test code (that runs successfully):
Server:
#include <windows.h>
#include <stdio.h>
int main() {
HANDLE mailslot = CreateMailslot("\\\\.\\mailslot\\myslot",
0,
MAILSLOT_WAIT_FOREVER,
NULL);
if (mailslot == INVALID_HANDLE_VALUE) {
fprintf(stderr, "Unable to create mailslot.");
return 1;
}
char buffer[2048];
OVERLAPPED ovlp = {0};
ovlp.hEvent = CreateEvent(NULL, false, false, NULL);
if (ovlp.hEvent == NULL) {
fprintf(stderr, "Unable to create Event.");
return 2;
}
DWORD read;
do {
ReadFile(mailslot, buffer, sizeof(buffer), &read, &ovlp);
buffer[read] = 0;
WaitForSingleObject(ovlp.hEvent, INFINITE);
printf("%s\n", buffer);
} while (strcmp(buffer, "exit"));
return 0;
}
Client:
#include <windows.h>
#include <stdio.h>
int main() {
HANDLE mailslot = CreateFile("\\\\.\\mailslot\\myslot",
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
0,
NULL);
if (INVALID_HANDLE_VALUE == mailslot) {
fprintf(stderr, "Unable to open mailslot.\n");
return 1;
}
char buffer[2048];
DWORD written;
for (int i=0; i<1024; i++)
buffer[i] = 'A' + (i%26);
buffer[1023] = '\0';
size_t len = strlen(buffer);
WriteFile(mailslot, buffer, len, &written, NULL);
WriteFile(mailslot, "exit", 4, &written, NULL);
return 0;
}
Result:
E:\C\source>mailslot
ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB
CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCD
EFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF
GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH
IJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ
KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKL
MNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN
OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP
QRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR
STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST
UVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV
WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX
YZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI
exit

Win32 API - Trying to readfile, it's getting truncated -- why?

I am trying to read a file and then display the file in ASCII or HEX into hEdit. Eventually I will be running other computations on the file info but right now I just want to see it all.
Currently the code displays the first bit - "MZ" - but thats it. Somehow I am accidentally truncating the pszFileText variable, I want to be able to view the entire executable in my window.
BOOL ReadInEXEFile(HWND hEdit, LPCTSTR pszFileName)
{
HANDLE hFile;
BOOL bSuccess = FALSE;
hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
DWORD dwFileSize;
dwFileSize = GetFileSize(hFile, NULL);
if(dwFileSize != 0xFFFFFFFF)
{
LPSTR pszFileText;
pszFileText = GlobalAlloc(GPTR, dwFileSize + 1);
if(pszFileText != NULL)
{
DWORD dwRead;
if(ReadFile(hFile, pszFileText, dwFileSize, &dwRead, NULL))
{
pszFileText[dwFileSize] = 0; // Add null terminator
if(SetWindowText(hEdit, pszFileText))
{
bSuccess = TRUE; // It worked!
}
}
GlobalFree(pszFileText);
}
}
CloseHandle(hFile);
}
return bSuccess;
}
EXE files are binary, but you are you trying to display the raw binary data as-is, which will not work. You were on the right track thinking that you need to encode the binary data to hex before displaying it. Binary data is not displayable, but hex is.
Try this instead:
static const TCHAR Hex[] = TEXT("0123456789ABCDEF");
BOOL ReadInEXEFile(HWND hEdit, LPCTSTR pszFileName)
{
BOOL bSuccess = FALSE;
HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD dwFileSize = GetFileSize(hFile, NULL);
if (dwFileSize != INVALID_FILE_SIZE)
{
LPTSTR pszFileText = (LPTSTR) LocalAlloc(LMEM_FIXED, ((dwFileSize * 3) + 1) * sizeof(TCHAR));
if (pszFileText != NULL)
{
BYTE buffer[1024];
DWORD dwOffset = 0;
DWORD dwRead;
for (DWORD dwFilePos = 0; dwFilePos < dwFileSize; dwFilePos += dwRead)
{
if (!ReadFile(hFile, buffer, sizeof(buffer), &dwRead, NULL))
{
CloseHandle(hFile);
return FALSE;
}
if (dwRead == 0)
break;
for (DWORD idx = 0; idx < dwRead; ++idx)
{
pszFileText[dwOffset++] = Hex[(buffer[idx] & 0xF0) >> 4];
pszFileText[dwOffset++] = Hex[buffer[idx] & 0x0F];
pszFileText[dwOffset++] = TEXT(' ');
}
}
pszFileText[dwOffset] = 0; // Add null terminator
bSuccess = SetWindowText(hEdit, pszFileText);
LocalFree(pszFileText);
}
}
CloseHandle(hFile);
}
return bSuccess;
}
Two reasons:
1) If you are reading an executable, the third byte is likely to be a zero, which might terminate the string, even though you are passing the length to SetWindowText.
2) This line is wrong: pszFileText[dwFileSize + 1] = 0;. It should be pszFileText[dwFileSize] = 0;. You are writing a zero byte some place wrong, there's no telling what that might be doing.
The way you are displaying it probably depends on the data being a NUL-terminated string, and binary data has embedded NULs in it, so you only display the data up to the first NUL.
You will need to print it by yourself and use the length of the data to know how much to print instead of depending on it being a NUL-terminated C-string.

Resources