I'm attempting to read a string from a dummy program with a kernel driver. But only the first 4 char's are being read, I can't figure out why.
Part of the IOCTL code for reading the string:
else if (ControlCode = IO_READ_STRING_REQUEST)
{
PREAD_REQUEST Values = (PREAD_REQUEST)buffer;
PREAD_REQUEST ValuesOutput = (PREAD_REQUEST)buffer;
PEPROCESS process;
if (NT_SUCCESS(PsLookupProcessByProcessId(PID, &process)))
{
KeReadProcessMemory(process, Values->Address, &ValuesOutput->buffer, Values->Size);
DbgPrint((PCSTR)Values->buffer);
status = STATUS_SUCCESS;
}
else
status = STATUS_INVALID_PARAMETER;
BytesIO = sizeof(READ_REQUEST);
}
This is the read struct:
typedef struct ReadStruct
{
ULONGLONG Address;
ULONGLONG Response;
ULONGLONG Size;
char buffer[128];
} READ_REQUEST, *PREAD_REQUEST;
The DbgPrint always prints stri when it's supposed to print stringChar, and stri is returned to the usermode.
This is how it's called from usermode:
void ReadString(std::string *string, DWORD64 address)
{
ReadValues Values;
std::memset(Values.buffer, '\0', 128);
Values.Address = address;
Values.Response = 0;
Values.Size = sizeof(128);
if (!(DeviceIoControl(hDriver, IO_READ_STRING_REQUEST, &Values, sizeof(Values), &Values, sizeof(Values), 0, 0)))
{
std::cout << "RPM Failed!\n";
exit(1);
}
*string = (std::string)Values.buffer;
}
The struct is the same:
struct ReadValues
{
ULONGLONG Address;
ULONGLONG Response;
ULONGLONG Size;
char buffer[128];
};
I thought it was the size, but when I specified the size to 11 (10 + \0) it also read only 4 chars.
The problem is here:
Values.Size = sizeof(128);
^^^^^^^^^^^
This is the same as sizeof(int) (which, I would guess, is 4 in your platform).
Either use 128 or sizeof(buffer) (the latter is arguably better since you won't be hard-coding the same constant in several places).
Related
I'm using CNG to generate a hash.
Result of BCryptFinishHash call is MD5 of a input in hex form.
Example:
char *outHash = "\x02\x34\x75\01..."
I want to convert it to printable string: 02347501...
How can I do that?
To encode a byte array in hex and write the encoded data to a std::string, do this:
static inline char
hex_digit(unsigned int n)
{
if (n < 10) return '0' + n;
if (n < 16) return 'a' + (n - 10);
abort();
}
std::string
encode_bytes(const unsigned char *bytes, size_t len)
{
std::string rv;
rv.reserve(len * 2);
for (size_t i = 0; i < len; i++) {
rv.push_back(hex_digit((bytes[i] & 0xF0) >> 4));
rv.push_back(hex_digit((bytes[i] & 0x0F) >> 0));
}
return rv;
}
Note that you must know the length of the byte array. It is not safe to treat it as a NUL-terminated "C string", because binary data can contain internal zero bytes. To know the length of a hash generated by CNG, call BCryptGetProperty to get the BCRYPT_HASH_LENGTH property.
we can use CryptBinaryToString here with CRYPT_STRING_HEXASCII or CRYPT_STRING_HEX or CRYPT_STRING_HEXRAW or CRYPT_STRING_HEX | CRYPT_STRING_NOCRLF or CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF depen how you want format string. for example
void print(PUCHAR pbHash, ULONG cbHash, DWORD dwFlags = CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF)
{
ULONG cch = 0;
if (CryptBinaryToStringW(pbHash, cbHash, dwFlags, 0, &cch))
{
if (PWSTR sz = (PWSTR)_malloca(cch * sizeof(WCHAR)))
{
if (CryptBinaryToStringW(pbHash, cbHash, dwFlags, sz, &cch))
{
DbgPrint("%S\n", sz);
}
_freea(sz);
}
}
}
If you need an easy, one time solution, this is a useful tool:
https://codebeautify.org/hex-string-converter
However, if you're looking to do this within your code itself, I found this from an earlier thread (AKA, this is not my work but that of #KEINE LUST from here )
int main(void)
{
unsigned char readingreg[4];
readingreg[0] = 0x4a;
readingreg[1] = 0xaa;
readingreg[2] = 0xaa;
readingreg[3] = 0xa0;
char temp[4];
sprintf(temp, "%x", readingreg[0]);
printf("This is element 0: %s\n", temp);
return 0;
}
You can print it like this:
for(const char *wsk=outHash; *wsk; ++wsk){
printf("%02hhx", *wsk);
}
Edit based that cstring can have 0x00 numbers.
C
const char outHash[] = "\x02\x34\x75";
const int size = sizeof(outHash)/sizeof(char) - 1;
for(int i = 0; i < size; ++i){
printf("%02hhx", outHash [i]);
}
C++
std::string outHash = "\x02\x34\x75";
for(int i = 0; i < outHash.size(); ++i) {
printf("%02hhx", outHash [i]);
}
Loop over the characters and print the numerical value (in hex).
#include <iostream>
#include <iomanip>
int main()
{
char* outHash = "\x02\x34\x75\x01\x23\xff"; // Get from your Hash function.
int sizeOfHash = 6; // Use appropriate size for BCryptFinishHash()
// Set up the characteristics of the stream.
// setw(2): Each printed object will use a min width of 2
// setfill('0'): If the object is less than 2 char then fill the space with '0'
// hex: Print numbers in hex.
std::cout << std::setw(2) << std::setfill('0') << std::hex;
// Create a view of the object.
// Makes it simpler to loop over.
std::string_view view(outHash, sizeOfHash);
// Loop over the string.
for(unsigned char val: view) {
// Convert to `unsigned char` to make sure you don't print
// negative numbers. Then convert from there to `int` so that
// the `std::hex will kick in and convert to hex value.
std::cout << static_cast<int>(val);
}
std::cout << "\n";
}
I am working on C++ wrapper around Windows Crypto API & CNG which I am using in my projects. I plan to move all of it to github but for now it is just a work in progress, but you can find it useful for Crypto basics like HEX / Base64 encode / decode etc.
https://github.com/m4x1m1l14n/Crypto
You can use Crypto::Hex::Encode() method to achieve what you want.
#include <Crypto\Hex.hpp>
#include <Crypto\Random.hpp>
using namespace m4x1m1l14n;
char arr[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0x99, 0x00 };
encoded = Crypto::Hex::Encode(arr, sizeof(arr));
/* encoded = "aabbccdd9900" */
Also you can use wrapper for MD5 which is located in Hash namespace, like this. (If you are not using large amount of data)
#include <Crypto\Hex.hpp>
#include <Crypto\Hash.hpp>
using namespace m4x1m1l14n;
encoded = Crypto::Hex::Encode(Crypto::Hash::MD5("Whatever you want to hash"));
There are tons of questions on this issue and I have been attempting the various solutions. There seems to be dozens of ways to do this however none of them are working. I am very new to C++ and VS, working for about a month, and I am trying to code an auto Excel program using VC++. I am stuck trying to concatenate a wchar_t * and an unsigned long long. I assume the first step is to "convert" the unsigned long long to wchar_t *. I apologize for throwing in the whole code but I think it may help with showing what I am aiming for and if there are any other weaknesses in the code.
wchar_t * ex(wchar_t * dest, unsigned long long num);
int main()
{
unsigned long long num = 10;
wchar_t *dest= L"A2:B";
wchar_t * Path=ex(dest, num);
VARIANT param;
param.vt = VT_BSTR;
// param.bstrVal = SysAllocString(L"A2:B10");
param.bstrVal = SysAllocString(Path);
getchar();
return 0;
}
wchar_t * ex(wchar_t * dest, unsigned long long num)
{
// Convert num to wchar_t *
wchar_t *rangeMax = (wchar_t *)num;
// I think this is used to eliminate extra space in other solutions
// but not here. It could be useful.
const int MAX_CHARS = 50;
size_t count = wcsnlen_s(dest, MAX_CHARS);
wprintf(L"The length of the string is %ld characters\n", count);
// Throw dest into buf
wchar_t buf[25] = { 0 };
int r = wcscpy_s(buf, 25, dest);
if (r != 0) {
wprintf(L"wcscpy_s() failed %ld", r);
}
r = wcscat_s(buf, 25, rangeMax);
if (r != 0) {
wprintf(L"wcscat_s() failed %ld", r);
}
wprintf_s(buf);
return buf;
}
ex is an edited example from zetcode. I think it is close to being the solution, however when combining buf and rangeMax the code throws all sorts of memory exceptions and fails.
As you can see the final destination for the concatenated wchar_t * is as a BSTR in a VARIANT through SysAllocString.
I appreciate any suggestions on code improvement as well as how to make the code actually run!
As suggested using wstring functioned as intended. Thank you for pointing out I was returning a pointer to a local variable! Once back in main the type was changed to wchar_t * which passed nicely to SysAllocString() for use with my main program.
std::wstring ex(wchar_t * dest, unsigned long long num);
int main()
{
unsigned long long num = 10;
wchar_t *dest= L"A2:B";
std::wstring PathString= ex(dest, num);
wchar_t *wPath = (WCHAR *)PathString.c_str();
std::wcout << L"In main\n";
std::wcout << wPath << L'\n';
VARIANT param;
param.vt = VT_BSTR;
//param.bstrVal = SysAllocString(L"A2:B10");
param.bstrVal = SysAllocString(wPath);
getchar();
return 0;
}
std::wstring ex(wchar_t * dest, unsigned long long num)
{
std::wstring rangeMax = std::to_wstring(num);
std::wstring string(dest);
string += rangeMax;
std::wcout << L"In function\n";
std::wcout<<string<<L'\n';
return string;
}
I have following piece of code that is supposed to calculate the SHA256 of a file. I am reading the file chunk by chunk and using EVP_DigestUpdate for the chunk. When I test the code with the file that has content
Test Message
Hello World
in Windows, it gives me SHA256 value of 97b2bc0cd1c3849436c6532d9c8de85456e1ce926d1e872a1e9b76a33183655f but the value is supposed to be 318b20b83a6730b928c46163a2a1cefee4466132731c95c39613acb547ccb715, which can be verified here too.
Here is the code:
#include <openssl\evp.h>
#include <iostream>
#include <string>
#include <fstream>
#include <cstdio>
const int MAX_BUFFER_SIZE = 1024;
std::string FileChecksum(std::string, std::string);
int main()
{
std::string checksum = FileChecksum("C:\\Users\\Dell\\Downloads\\somefile.txt","sha256");
std::cout << checksum << std::endl;
return 0;
}
std::string FileChecksum(std::string file_path, std::string algorithm)
{
EVP_MD_CTX *mdctx;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
int i;
unsigned int md_len;
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(algorithm.c_str());
if(!md) {
printf("Unknown message digest %s\n",algorithm);
exit(1);
}
mdctx = EVP_MD_CTX_create();
std::ifstream readfile(file_path,std::ifstream::in|std::ifstream::binary);
if(!readfile.is_open())
{
std::cout << "COuldnot open file\n";
return 0;
}
readfile.seekg(0, std::ios::end);
long filelen = readfile.tellg();
std::cout << "LEN IS " << filelen << std::endl;
readfile.seekg(0, std::ios::beg);
if(filelen == -1)
{
std::cout << "Return Null \n";
return 0;
}
EVP_DigestInit_ex(mdctx, md, NULL);
long temp_fil = filelen;
while(!readfile.eof() && readfile.is_open() && temp_fil>0)
{
int bufferS = (temp_fil < MAX_BUFFER_SIZE) ? temp_fil : MAX_BUFFER_SIZE;
char *buffer = new char[bufferS+1];
buffer[bufferS] = 0;
readfile.read(buffer, bufferS);
std::cout << strlen(buffer) << std::endl;
EVP_DigestUpdate(mdctx, buffer, strlen(buffer));
temp_fil -= bufferS;
delete[] buffer;
}
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
EVP_MD_CTX_destroy(mdctx);
printf("Digest is: ");
//char *checksum_msg = new char[md_len];
//int cx(0);
for(i = 0; i < md_len; i++)
{
//_snprintf(checksum_msg+cx,md_len-cx,"%02x",md_value[i]);
printf("%02x", md_value[i]);
}
//std::string res(checksum_msg);
//delete[] checksum_msg;
printf("\n");
/* Call this once before exit. */
EVP_cleanup();
return "";
}
I tried to write the hash generated by program as string using _snprintf but it didn't worked. How can I generate the correct hash and return the value as string from FileChecksum Function? Platform is Windows.
EDIT: It seems the problem was because of CRLF issue. As Windows in saving file using \r\n, the Checksum calculated was different. How to handle this?
MS-DOS used the CR-LF convention,So basically while saving the file in windows, \r\n comes in effect for carriage return and newline. And while testing on online (given by you), only \n character comes in effect.
Thus either you have to check the checksum of Test Message\r\nHello World\r\n in string which is equivalent to creating and reading file in windows(as given above), which is the case here.
However, the checksum of files,wherever created, will be same.
Note: your code works fine :)
It seems the problem was associated with the value of length I passed in EVP_DigestUpdate. I had passed value from strlen, but replacing it with bufferS did fixed the issue.
The code was modified as:
while(!readfile.eof() && readfile.is_open() && temp_fil>0)
{
int bufferS = (temp_fil < MAX_BUFFER_SIZE) ? temp_fil : MAX_BUFFER_SIZE;
char *buffer = new char[bufferS+1];
buffer[bufferS] = 0;
readfile.read(buffer, bufferS);
EVP_DigestUpdate(mdctx, buffer, bufferS);
temp_fil -= bufferS;
delete[] buffer;
}
and to send the checksum string, I modified the code as:
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
EVP_MD_CTX_destroy(mdctx);
char str[128] = { 0 };
char *ptr = str;
std::string ret;
for(i = 0; i < md_len; i++)
{
//_snprintf(checksum_msg+cx,md_len-cx,"%02x",md_value[i]);
sprintf(ptr,"%02x", md_value[i]);
ptr += 2;
}
ret = str;
/* Call this once before exit. */
EVP_cleanup();
return ret;
As for the wrong checksum earlier, the problem was associated in how windows keeps the line feed. As suggested by Zangetsu, Windows was making text file as CRLF, but linux and the site I mentioned earlier was using LF. Thus there was difference in the checksum value. For files other than text, eg dll the code now computes correct checksum as string
I want to exchange data over TCP/IP with C++ by writing my own small binary protocol. My idea was to implement the protocol by defining values in form of the following bytes:
BEGIN
LENGTH
FUNCTIONCODE
[data bytes] (optional)
CRC
END
How can I define a binary value for "BEGIN" that is unique allowing the receiver to recognize the beginning of a new telegram? E.g. if I do that:
static const int BEGIN = 0x41;
and the optional data bytes randomly include also the 0x41 value, this might be a problem for the receiver. Or am I wrong? If not, how may I define a unique BEGIN and END value?
I usually write something like this for simple C++ networking. (But I wrote this code from scratch this time and haven't tested it at all!)
class Packet : public std::string {
public:
struct __attibute__((__packed__)) Header {
static const int BEGIN = 0x41;
uint32_t begin;
uint16_t length;
uint16_t funcode;
void init(uint16_t len) { begin = BEGIN; length = len; }
bool verify() { return (BEGIN == begin); }
char *buffer() { return reinterpret_cast<char *>(this); }
};
class __attibute__((__packed__)) Footer {
uint32_t crc;
char term;
char newline;
void init() { term = ';'; newline = '\n'; }
bool verify() { return (';' == term && '\n' == newline); }
char *buffer() { return reinterpret_cast<char *>(this); }
};
public:
void init(size_t n = 0) {
resize(sizeof(Header) + n + sizeof(Footer));
Header * const h = header();
h->init(n);
Footer * const f = footer();
f->init();
}
// these two are valid only after init()
Header *header() { return reinterpret_cast<Header*>(&(*this)[0]); }
Footer *footer() { return reinterpret_cast<Footer*>(&(*this)[size() - sizeof(Footer)]); }
template <typename T>
T *buffer() { return reinterpret_cast<T *>(&(*this)[sizeof(Header)]); }
void extend(size_t n) { resize(size() + n); }
};
int sendMessage(int funcode) {
Packet p;
switch (funcode) {
case TIME: {
timeval tv;
gettimeofday(&tv, NULL);
p.init(sizeof tv);
Packet::Header * const h = p.header();
h->funcode = funcode;
timeval * const dst = p.buffer<timeval>();
*dst = tv;
} break;
case PID: {
const pid_t pid = getpid();
p.init(sizeof pid);
Packet::Header * const h = p.header();
h->funcode = funcode;
pid_t * const dst = p.buffer<pid_t>();
*dst = pid;
} break;
...
}
Packet::Footer * const f = p.footer();
f->crc = ...;
const ssize_t nSent = send(sock, p.data(), p.size(), 0);
...
}
Packet receiveMessage() {
Packet ret;
ret.init();
Packet::Header * const h = ret.header();
ssize_t nRecv = recv(sock, h->buffer(), sizeof *h, 0);
...
if ( ! h->verify()) ...
p.extend(h->length);
nRecv = recv(sock, p.buffer<char>(), h->length, 0);
switch (h->funcode) {
case TIME: {
timeval tv = *p->buffer<timeval>();
tm theTm;
localtime_r(&tv.tv_sec, &theTm);
char buf[128];
strftime(buf, sizeof buf, "%x %X", &tv);
cout << "Server time == " << buf << endl;
} break;
case PID: {
const pid_t pid = *p.buffer<pid_t>();
cout << "Server PID == " << pid << endl;
} break;
...
}
Packet::Footer * const f = ret.footer();
nRecv = recv(sock, f->buffer(), sizeof *f, 0);
if ( ! f->verify() || f->crc != ...) ...
return ret; // inefficient data copy, only for a sample code
}
I recommend you to define your BEGIN code as something like 0x48454c4f which can be read as ASCII "HELO" rather than a random int like 0x41. And I added two extra bytes ';' and '\n'to the footer; you will find them useful when you dump packet capture of your protocol to the console. Remember, you can always use sed, perl, python or whatever (but not grep; it won't accept arbitrary hex search strings) to analyse arbitrary binary data including your packet dump. If you design your protocol well, your debugging will be much easier. (First of all, you should consider using ASCII protocol rather than binary one.)
Frequently a protocol definition goes like this:
FUNCTIONCODE
LENGTH
DATA
CRC
and there's no need to fish for "BEGIN". Reading proceeds by reading FUNCTIONCODE and LENGTH using a fixed length, and then the data + CRC, according to LENGTH, and then, again...
However, if you think that the additional "BEGIN" marker helps you, select "BEGIN" as a value that's not a FUNCTIONCODE, and then you have
BEGIN
FUNCTIONCODE
LENGTH
DATA
CRC
And for every byte after BEGIN equal to BEGIN send BEGIN twice. But, in this case, reading is much more complicated...
I was making a re-creation of some System.IO functions from that class.
When I setup a buffer and allocate n number of bytes it'll read bytes to that and then add random bytes to the end of that buffer.
For example:
My Main:
int main(int argc, char *args[])
{
SetConsoleTitle(TEXT("Stream Test."));
cout<<"Press any Key to begin reading.";
cin.get();
const char* data = File::ReadAllBytes(args[1]);
Stream* stream = new Stream(data);
char* magic = new char[8];
stream->Read(magic, 0, 8);
magic[8] = '\0';
cout<<magic<<endl<<endl;
delete[]data;
cout<<"Press any key to quit.";
cin.get();
return 0;
}
and here is my System::IO namespace + stream class:
namespace System
{
namespace IO
{
class File
{
public:
static char* ReadAllBytes(const char *name)
{
ifstream fl(name, ifstream::in|ifstream::binary);
fl.seekg( 0, ifstream::end );
size_t len = fl.tellg();
char* ret = new char[len+1];
ret[len] = '\0';
fl.seekg(0);
fl.read(ret, len);
fl.close();
return ret;
}
//not sure of this use yet.
static size_t fileSize(const char* filename)
{
ifstream in(filename, ifstream::in | ifstream::binary);
in.seekg(0, ifstream::end);
return in.tellg();
}
};
class Stream
{
public:
const char *_buffer;
__int64 _origin;
__int64 _position;
__int64 _length;
__int64 _capacity;
bool _expandable;
bool _writable;
bool _exposable;
bool _isOpen;
static const int MemStreamMaxLength = 2147483647;
Stream()
{
InitializeInstanceFields();
}
Stream(const char *buffer)
{
_buffer = buffer;
_length = strlen(_buffer);
_capacity = _length;
_position = 0;
_origin = 0;
_expandable = false;
_writable = true;
_exposable = true;
_isOpen = true;
}
int ReadByte()
{
if (_position >= _length)
return -1;
return _buffer[_position++];
}
void Read(char* &buffer, int offset, int length)
{
if((_position + offset + length) <= _length)
{
memcpy( buffer, _buffer + (_position + offset), length );
_position += length;
}
}
private:
void InitializeInstanceFields()
{
_origin = 0;
_position = 0;
_length = 0;
_capacity = 0;
_expandable = false;
_writable = false;
_exposable = false;
_isOpen = false;
}
};
}
}
This is what ends up happening:
Can anyone explain why this happens, how I can fix, or anything else? I'm new to C++ so any explanations would help. Also please don't criticize my scripting, I know it may be bad, outdated, deprecated, etc. but I'm open to learning and any helping advice goes for the better. :)
You can only use operator << (char *) on C-style strings, not arbitrary arrays of characters. How would you expect it to know how many characters to output?
I would guess the file was not opened correctly and thus the magic buffer is not set at all which leaves it with initialized junk data:
If the constructor is not successful in opening the file, the object
is still created although no file is associated to the stream buffer
and the stream's failbit is set (which can be checked with inherited
member fail).
http://www.cplusplus.com/reference/fstream/ifstream/ifstream/
Try adding more error checking along the way (using cout), especially when opening and reading the buffer. Perhaps set the magic buffer to zero or something recognizable that is overwritten when successful.