How to properly call _vsnprintf from a DLL - c++

I am trying to execute a game function that displays text to the chat screen. I pulled the address from IDA that then calls _vsnprintf. I can get it to display text to the chat but its wonky random letters that changes whenever I mess with the argList. Heres the constructor for _vsnprintf.
int __cdecl _vsnprintf(char *const Buffer, const size_t BufferCount, const char *const Format, va_list ArgList) //0xA739FF
Whenever I change something in ArgList it changes the text result but the text displayed in chat is still random and wonky.
Also this is the function that calls _vsnprintf
int __cdecl print_to_chat(char *Buffer, size_t BufferCount, char *Format, char ArgList) //0x51D020
And here is the code I got so far
namespace bo2 {
constexpr uintptr_t say = 0x7EB870;
constexpr uintptr_t printf = 0xA739FF;
using say_t = void(*)();
using printf_t = void(*)(char* const Buffer, const size_t BufferCount, const char* const Format, va_list ArgList);
}
BOOL APIENTRY DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
if (reason == DLL_PROCESS_ATTACH) {
const auto say = reinterpret_cast<bo2::say_t>(bo2::say);
const auto printf = reinterpret_cast<bo2::printf_t>(bo2::printf);
char buf[255], format[255]; size_t size = 256; std::string rV = "does this work now??????";
va_list list;
va_start(list, rV);
say();
printf(buf, size, format, list);
}
}
Any help?
I tried editing Format to get a proper display to chat text but that doesn't seem to be it after realizing whatever was edited in ArgList contributed to a proper yet random and wonky return of text to chat.
EDIT: Im now only calling _vsnprintf instead of print_to_chat and using va_list instead of const char* or char*

Related

What is the appropriate way to pass given vararg parameter to another function?

I've begun works on a hook/event system in C++. This system is supposed to handle all sorts of events as notified by other parts of the application.
The issue I've faced is with the way I want it to run.
Generally, I want it to be so that you call a specific function with all arguments you wish to pass on, and then that function handles calling all registered hooks of that specific event, passing them on the arguments, retrieving their result values and returning it to the original caller.
Generally, this is how it was supposed to look:
CHookReturn* bInitializationStatus = Hook::Run("Initialize", gGame);
CHookReturn* bThinkSuccessful = Hook::Run("Think");
However, I ran into one issue.
I set it up in such way that the Run function in the Hook namespace, calling the Run function of the CHookData_t structure, needs to pass on varargs. I couldn't find any other way. This is how it ended up:
union CHookReturn
{
const char* m_pszValue;
int m_iValue;
float m_flValue;
double m_dlValue;
bool m_bValue;
};
struct CHookData_t
{
virtual void Run(CHookReturn* ret, ...) = 0;
};
namespace Hook
{
std::unordered_map<const char*, std::unordered_map<const char*, CHookData_t*>> umHookList;
bool Add(const char*, const char*, CHookData_t*);
bool Exists(const char*, const char*);
bool Remove(const char*, const char*);
int Count(const char*);
CHookReturn* Run(const char*, ...);
};
CPP file segment of the Hook::Run function:
CHookReturn* Hook::Run(const char* eventName, ...)
{
// FIXME: Look into alternative execution.
// This code seems more like a workaround
// than what I originally wanted it to be.
int count = Hook::Count(eventName);
CHookReturn* returnValues = new CHookReturn[count];
int c = 0;
unordered_map<const char*, CHookData_t*>::iterator itr;
unordered_map<const char*, CHookData_t*> res;
res = umHookList.at(eventName);
va_list valist;
void* args;
va_copy(args, valist);
for (itr = res.begin(); itr != res.end(); itr++)
{
CHookReturn returnData;
itr->second->Run(&returnData, args);
returnValues[c] = returnData;
++c;
}
return returnValues;
}
The above code brings up two warnings which make me question if it is a good idea to execute it in this way, as well as whether there are any alternatives I should look into.
The warnings I received were:
Warning C6001 Using uninitialized memory 'valist'.
Warning C6386 Buffer overrun while writing to 'returnValues': the writable size is 'count*8' bytes, but '16' bytes might be written.
Is there a better way to do this?
Fixing your code using va_list:
struct CHookData_t
{
virtual ~CHookData_t() {}
virtual void Run(CHookReturn* ret, va_list arg) = 0;
};
namespace Hook
{
using HooksList = std::unordered_map<
std::string,
std::unordered_map<std::string, std::unique_ptr<CHookData_t>>;
HooksList umHookList;
...
}
std::vector<CHookReturn> Hook::Run(const std::string& eventName, ....)
{
va_list valist;
va_start(valist, eventName);
auto result = Hook::RunVarg(eventName, valist);
va_end(valist);
return result;
}
std::vector<CHookReturn> Hook::RunVarg(const std::string& eventName, va_list arg)
{
int count = Hook::Count(eventName);
std::vector<CHookReturn> returnValues(count);
size_t c = 0;
for (auto& item : umHookList.at(eventName))
{
va_list arg_copy;
va_copy(arg_copy, arg);
item.second->Run(&returnValues[c], arg_copy);
va_end(arg_copy);
++c;
}
return returnValues;
}
I have no idea what are arguments of Hook::Run what va_list points to, so I can't you provide nice C++ solution.
Note that va_copy is needed inside of loop, since some compilers (don't remembered which, possibly msvc) va_list behaves like a pointer and reading arguments from it will have impact on each iteration. On other compilers va_list behaves like a value and va_copy do not change anything.
offtopic: your code is to much C, you shouldn't use const char* but std::string or std::string_view if you are using C++17, instead va_args it would be better to use variadic template or std::initializer_list, avoid raw pointers in favor of std::unique_ptr and std::shared_ptr. I've tweaked your code a bit to cover that.
Also Hook should not be a namespace, by the look of functions and variables it contains it should be a class, so you should fix it too.

Read file content in SGX enclave

I'm trying to read the content of a file from an enclave using OCalls.
enclave.edl:
untrusted {
void ocall_print_string([in, string] const char *str);
void ocall_read_IMA_file([in, string] const char *filename, [out] char *buf, [out] int *size);
};
enclave.cpp:
void printf(const char *fmt, ...) {
ocall_print_string(fmt);
}
void read_IMA_file(const char *filename, char *buf, int *size) {
ocall_read_IMA_file(filename, buf, size);
printf(buf);
}
//whereas the read_IMA_file function is called with
char *buf;
int size;
read_IMA_file("test.txt", buf, &size);
implementation of ocall functions in the application:
void ocall_print_string(const char *str) {
printf("%s\n", str);
}
void ocall_read_IMA_file(const char *filename, char *content, int *size) {
content = (char*) malloc(sizeof(char) * 10);
memset(content, '\0', sizeof(char) *10);
char tmp[] = "1234567890";
copy(&tmp[0], &tmp[9], content);
cout << content << endl;
}
But the result I receive is the following:
123456789 (null)
I'm not sure what I'm doing wrong?
In the above program, the "read_IMA_file" trusted function is called with pointer variable(OUT pointer) of type character.Here we are passing the pointer variable without any memory allocation.
"read_IMA_file" initiate a OCall that allocate memory and do "Copy" operation.Now the allocated memory is valid within the untrusted region. So we are getting expected result for the "cout<
Since there is no trusted memory allocated for "content"(before calling Ocall), no copy back operation happens in "OUT" pointer during Ocall returns.
So "buf" doesn't contain any valid data while doing "print(buf)" after Ocall returns in trusted region.
Please try with valid OUT pointer to character buffer(with some memory allocation) or IN and OUT pointer to String buffer.
If you expect it to output 1234567890, then you may need to malloc(11) instead of malloc(10), plus the way you are using copy may contain a bug too.
copy(&tmp[0], &tmp[9], content);
is copying 123456789 to the content, it exclude the the last iterator &tmp[9] as I understand. For more detail, you may want to look at: http://www.cplusplus.com/reference/algorithm/copy/
Also, I think you are not reading in any content from file "test.txt" either.

const_cast with two levels pointers

I want to do this conversion using C++ format, it works on the C way. but it fails when I try on C++ format.
It works!
void req_password(const void *data, size_t datalen)
{
char *password_old = ((char **) data)[0];
char *password_new = ((char **) data)[1];
...
}
It fails
void req_password(const void *data, size_t datalen)
{
char *password_old = (const_cast<char **>(data))[0];
char *password_old = (const_cast<char **>(data))[1];
...
}
error:
error: invalid const_cast from type 'const void*' to type 'char**'
So my doubt is, how could I do this conversion using the C++ way?
PS: This code is part from a API, I can't control the the input of data.
Don't.
If you are being given immutable data, then you are being given immutable data and that is the end of it!
First, here's what I suggest for maximum safety. Coercing data into its real type is a little tricky, alas:
void req_password(const void* data, size_t datalen)
{
const char* password_old = (reinterpret_cast<const char* const*>(data)[0]);
const char* password_new = (reinterpret_cast<const char* const*>(data)[1]);
// ...
}
(I've actually added some constness in the above, as it seems to be the intent of having const void* in the first place.)
But, if you really want the strings to be mutable, then this is fine too:
void req_password(const void* data, size_t datalen)
{
char* password_old = (reinterpret_cast<char* const*>(data)[0]);
char* password_new = (reinterpret_cast<char* const*>(data)[1]);
// ...
// More obvious when you recall that `const void*` is actually `void const*`;
// So:
// void const*
// becomes:
// char* const*
}
Notice how you don't even need const_cast here, because you're not modifying the thing that data points to: you are dereferencing it and getting its pointee.
Of course, ideally, data would point to a const std::string instance.

Wrapping FindFirstFile/FindNextFile/FindClose in a DLL

I have a DLL written in C++ that wraps FindFirstFile/FindNextFile/FindClose to provide a file-search function:
std::vector<std::wstring> ELFindFilesInFolder(std::wstring folder, std::wstring fileMask = TEXT(""), bool fullPath = false);
This function returns a std::vector containing a list of filenames within the given folder matching the given filemask. So far so good; the function works as expected.
I need to write a C wrapper around this library, though, because I can't pass a vector across DLL boundaries. This is leading to no end of headaches.
I initially thought I would just set up a function that would receive a two-dimensional wchar_t array, modify it to contain the filename list, and return it:
bool ELFindFilesInFolder(const wchar_t* folderPath, const wchar_t* fileMask, const bool fullPath, wchar_t* filesBuffer[], size_t* filesBufferSize);
This proved to be a bad idea, however, as at least the second dimension's size has to be known at compile-time. I suppose I could just force the caller to make the second dimension MAX_PATH (so the function would receive a variable-length list of filename buffers, each MAX_PATH long), but this seems messy to me.
I considered a wrapper in the style of the Windows APIs:
bool ELFindNextFileInFolder(const wchar_t* folderPath, const wchar_t* fileMask, const bool fullPath, wchar_t* fileBuffer, size_t* fileBufferSize, HANDLE* searchToken);
This would perform the search, return the first filename found, and save the search handle provided by FindFirstFile. Future calls to ELFindNextFileInFolder would provide this search handle, making it easy to pick up where the last call left off: FindNextFile would just get the saved search handle. However, such handles are required to be closed via FindClose, and C doesn't seem to have the C++ concept of a smart pointer so I can't guarantee the searchToken will ever be closed. I can close some of the HANDLEs myself when FindNextFile indicates there are no more results, but if the caller abandons the search before that point there'll be a floating HANDLE left open. I'd very much like my library to be well-behaved and not leak HANDLEs everywhere, so this is out. I'd also prefer not to provide an ELCloseSearchHandle function, since I'm not sure I can trust callers to use it properly.
Is there a good, preferably single-function way to wrap these Windows APIs, or am I simply going to have to pick one from a list of imperfect solutions?
What about something like this?
In the DLL module:
#include <windows.h>
#include <vector>
#include <unordered_map>
unsigned int global_file_count; //just a counter..
std::unordered_map<unsigned int, std::vector<std::wstring>> global_file_holder; //holds vectors of strings for us.
/** Example file finder C++ code (not exported) **/
std::vector<std::wstring> Find_Files(std::wstring FileName)
{
std::vector<std::wstring> Result;
WIN32_FIND_DATAW hFound = {0};
HANDLE hFile = FindFirstFileW(FileName.c_str(), &hFound);
if (hFile != INVALID_HANDLE_VALUE)
{
do
{
Result.emplace_back(hFound.cFileName);
} while(FindNextFileW(hFile, &hFound));
}
FindClose(hFile);
return Result;
}
/** C Export **/
extern "C" __declspec(dllexport) unsigned int GetFindFiles(const wchar_t* FileName)
{
global_file_holder.insert(std::make_pair(++global_file_count, Find_Files(FileName)));
return global_file_count;
}
/** C Export **/
extern "C" __declspec(dllexport) int RemoveFindFiles(unsigned int handle)
{
auto it = global_file_holder.find(handle);
if (it != global_file_holder.end())
{
global_file_holder.erase(it);
return 1;
}
return 0;
}
/** C Export **/
extern "C" __declspec(dllexport) const wchar_t* File_Get(unsigned int handle, unsigned int index, unsigned int* len)
{
auto& ref = global_file_holder.find(handle)->second;
if (ref.size() > index)
{
*len = ref[index].size();
return ref[index].c_str();
}
*len = 0;
return nullptr;
}
/** C Export (really crappy lol.. maybe clear and reset is better) **/
extern "C" __declspec(dllexport) void File_ResetReferenceCount()
{
global_file_count = 0;
//global_file_holder.clear();
}
extern "C" __declspec(dllexport) bool __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, void* lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return true;
}
Then in the C code you can use it like:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main()
{
HMODULE module = LoadLibrary("CModule.dll");
if (module)
{
unsigned int (__cdecl *GetFindFiles)(const wchar_t* FileName) = (void*)GetProcAddress(module, "GetFindFiles");
int (__cdecl *RemoveFindFiles)(unsigned int handle) = (void*)GetProcAddress(module, "RemoveFindFiles");
const wchar_t* (__cdecl *File_Get)(unsigned int handle, unsigned int index, unsigned int* len) = (void*)GetProcAddress(module, "File_Get");
void (__cdecl *File_ResetReferenceCount)() = (void*)GetProcAddress(module, "File_ResetReferenceCount");
unsigned int index = 0, len = 0;
const wchar_t* file_name = NULL;
unsigned int handle = GetFindFiles(L"C:/Modules/*.dll"); //not an actual handle!
while((file_name = File_Get(handle, index++, &len)) != NULL)
{
if (len)
{
wprintf(L"%s\n", file_name);
}
}
RemoveFindFiles(handle); //Optional..
File_ResetReferenceCount(); //Optional..
/** The above two functions marked optional only need to be called
if you used FindFiles a LOT! Why? Because you'd be having a ton
of vectors not in use. Not calling it has no "leaks" or "bad side-effects".
Over time it may. (example is having 500+ (large) vectors of large strings) **/
FreeLibrary(module);
}
return 0;
}
It seems a bit dirty to be honest but I really don't know any "amazing" ways of doing it. This is just the way I do it.. Most of the work is done on the C++ side and you don't really have to worry about leaks.. Even exporting a function to clear the map would be nice too..
It would be better if the C exports were added to a template class and then export each of those.. That would make it re-useable for most C++ containers.. I think..
Change wchar_t* filesBuffer[] to wchar_t** *filesBuffer, then the caller can pass in a pointer to a wchar_t** variable to receive the array and does not need to know anything about any bounds at compile time. As for the array itself, the DLL can allocate a one-dimensional array of wchar_t* pointers that point to null-terminated strings. That way, your size_t* filesBufferSize parameter is still relevant - it receives the number of strings in the array.
bool ELFindFilesInFolder(const wchar_t* folderPath, const wchar_t* fileMask, const bool fullPath, wchar_t** *filesBuffer, size_t* filesBufferSize);
wchar_t **files;
size_t numFiles;
if (ELFindFilesInFolder(..., &files, &numFiles))
{
for(size_t i = 0; i < numFiles; ++i)
{
// use files[i] as needed ...
}
// pass files back to DLL to be freed ...
}
Another option is to do something similar to WM_DROPFILES does. Have ELFindFilesInFolder() return an opaque pointer to an internal list, and then expose a separate function that can retrieve a filename at a given index within that list.
bool ELFindFilesInFolder(const wchar_t* folderPath, const wchar_t* fileMask, const bool fullPath, void** filesBuffer, size_t* filesBufferSize);
bool ELGetFile(const wchar_t* fileName, size_t fileNameSize, void* filesBuffer, size_t fileIndex);
void *files;
size_t numFiles;
wchar_t fileName[MAX_PATH + 1];
if (ELFindFilesInFolder(..., &files, &numFiles))
{
for(size_t i = 0; i < numFiles; ++i)
{
ELGetFile(fileName, MAX_PATH, files, i);
// use fileName as needed ...
}
// pass files back to DLL to be freed ...
}
Any way you do it, the DLL has to manage the memory, so you have to pass some kind of state info to the caller and then have that passed back to the DLL for freeing. There is no many ways around that in C, unless the DLL keeps track of the state info internally (but then you have to worry about thread safety, reentrancy, etc) and frees it after the last file is retrieved. But that would require the caller to reach the last file, whereas the other approaches allow the caller to finish earlier if desired.

Correctly setting up parameters in C# when calling C++ DLL

I've been tasked with putting a C# wrapper around an old C++ dll that has had the source mislaid. I do have some details of the dll:
enum DataItemType {DataItemType_String, DataItemType_Number, DataItemType_Date};
typedef struct Data_Item_Node_
{
char *field_name;
char *field_value;
enum DataItemType field_type;
struct Data_Item_Node_ *next;
} Data_Item_Node;
typedef struct Data_Item_List_
{
Data_Item_Node *first; // points to first item in the list
Data_Item_Node *last; // points to last item in the list
long count; // number of data items in the list
Data_Item_Node **index; // sorted array of pointers to the list items
char *pDataDumpBuffer; // pointer to a buffer used by the [*DumpData] command
} Data_Item_List;
extern "C" SAIL_IMP_EXP BOOL WINAPI Sail_Validate(const char *sail, const char *streams, const char *inserts)
extern "C" SAIL_IMP_EXP BOOL WINAPI Sail_GetStreamAndInserts(char *sail, Data_Item_List_ *data, char *stream, char inserts[][9], int insert_count)
extern "C" SAIL_IMP_EXP LONG WINAPI Sail_GetErrorMessage(LPSTR error, DWORD len)
As you can see, there are 3 methods I need to call. I've created a C# command line wrapper to test it with and used DLLImport to reference the exposed methods:
class Program
{
[DllImport("Sail_.dll")]
public static extern bool Sail_Validate(string sail, string streams, string inserts);
static void Main(string[] args)
{
string p_sail = args[0];
string p_streams = args[1];
string p_inserts = args[2];
try
{
bool Result = Sail_Validate(p_sail, p_streams, p_inserts);
Console.WriteLine("Result: " + Result.ToString());
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
This C# code seems to work so far for the one method it calls, but I've hit a bit of a brick wall at the next one 'Sail_GetStreamAndInserts', mainly with the Data_Item_List_ & 2 dimensional array parameters.
I'd be grateful for any help in how to define the parameters for the remaining methods.