C++ chars stored in the LPCSTR .. broken? - c++

LPCSTR dllPath = ExePath().append("\\").append(DEF_INJECT_DLL).c_str();
DWORD dwBufSize = (DWORD)(strlen(dllPath) + 1) * sizeof(LPCSTR);
/* test */
char tbuf[1024]= {0,};
sprintf_s(tbuf, "dllPath : %s\r\ndwBufSize : %d", dllPath, dwBufSize);
MessageBoxA(NULL, tbuf, "TEST", MB_OK);
part of the code to inject my dll.
ExePath() is a function to get AbsolutePath of std::string data type using GetModuleFileNameA API and so on.
DEF_INJECT_DLL is defined by #define "MyDll.dll"
But when I run this code, it shows me broken strings....
And, when I change the MessageBoxA to this:
MessageBoxA(NULL,
ExePath().append("\\").append(DEF_INJECT_DLL).c_str(),
"TEST",
MB_OK);
it shows properly?
Also, I tried in this way:
MessageBoxA(NULL,dllPath, "TEST", MB_OK);
but it shows to me like first screenshot.
What is the problem?

The problem is in this line:
LPCSTR dllPath = ExePath().append("\\").append(DEF_INJECT_DLL).c_str();
here you call ExePath(), which returns a std::string instance, modify it, and finally call c_str() to get the raw data buffer.
However, the return value is a temporary object. After that line, the returned std::string is deleted, and will clean its memory. Therefore, the address where dllPath points to is no longer valid!
You could store the return value in a local instance, e.g.
std::string str = ExePath().append("\\").append(DEF_INJECT_DLL);
LPCSTR dllPath = str.c_str();

Related

Read the file version of a dll in C: The system cannot find the file specified

I am new in the forum but I have already found a lot of help for my other projects.
I am using Visual Studio 2019 and I have created a .rc file which contains the file version and a few other things. These information are displayed in the Properties window of the my dll correctly.
I have created a function
void PrintVersion(TCHAR* pszFilePath, void (*printFunc)(const char*, ...));
which receives the file path and a pointer to my logger function. Inside that function I want to read the file version and print it to the logger. But my logger returns Error in GetFileVersionInfoSize: The system cannot find the file specified.
My function call does look like this:
TCHAR* filename = L"mydll.dll";
PrintVersion(filename, gPrintFunc);
And the function is implemented as follows:
// Read the version of the dll and write it to the logger
void PrintVersion(TCHAR* pszFilePath, void (*printFunc)(const char*, ...))
{
DWORD dwSize = 0;
DWORD verHandle = 0;
BYTE* pbVersionInfo = NULL;
VS_FIXEDFILEINFO* pFileInfo = NULL;
UINT puLenFileInfo = 0;
// Get the size of the version information. This is done to check if the file is avaialbe
// If the size is zero then a error occured
dwSize = GetFileVersionInfoSize(pszFilePath, &verHandle);
if (dwSize == 0)
{
gPrintFunc("Error in GetFileVersionInfoSize: ");
PrintLastErrorString(gPrintFunc);
return;
}
// Create some memory for the file version info
pbVersionInfo = malloc(dwSize);
// Store the information into pbVersionInfo
#pragma warning(suppress : 6387)
if (!GetFileVersionInfo(pszFilePath, verHandle, dwSize, pbVersionInfo))
{
gPrintFunc("Error in GetFileVersionInfo: ");
PrintLastErrorString(gPrintFunc);
free(pbVersionInfo);
return;
}
// Make the information easier accessable in pFileInfo
#pragma warning(suppress : 6387)
if (!VerQueryValue(pbVersionInfo, TEXT("\\"), (LPVOID*)&pFileInfo, &puLenFileInfo))
{
gPrintFunc("Error in VerQueryValue: ");
PrintLastErrorString(gPrintFunc);
free(pbVersionInfo);
return;
}
// pFileInfo->dwFileVersionMS and pFileInfo->dwFileVersionLS contain the software version
// Major2B.Minor2B.Revision2B.Build2B
gPrintFunc("File Version of %s: %d.%d.%d.%d\n",
pszFilePath,
(pFileInfo->dwFileVersionMS >> 16) & 0xffff,
(pFileInfo->dwFileVersionMS >> 0) & 0xffff,
(pFileInfo->dwFileVersionLS >> 16) & 0xffff,
(pFileInfo->dwFileVersionLS >> 0) & 0xffff
);
// Free up the reserved memory
free(pbVersionInfo);
}
// Used for receiving the last WIN32 error and write it to the logger
void PrintLastErrorString(void (*printFunc)(const char*, ...))
{
// Get the error id of the last error
DWORD iLastError;
iLastError = GetLastError();
//Ask Win32 to give us the string version of that message ID.
//The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
LPSTR messageBuffer = NULL;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, iLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
gPrintFunc("%s\n", messageBuffer);
return;
}
I created that function by combining a few different C++ and C# examples from this forum. I am not familiar with the TCHAR* datatype. I assume that the problem has maybe something to do with the filename string. Further I am not able to print the filename to the logger with the %s format placeholder. In this case only the first letter of the filename is displayed.
One further info. Before I copied that code to the dll. I created a small console application. And in this case it was possible to read the file version of the exe. I also tried to specify the complete path of the dll. The dll and the exe, which uses the dll are in the same directory.
Maybe someone can help me :)
BR
Thank you for your answers.
I changed now the character set to: Use Unicode Character Set and now it works as expected.

How to get the logged-on user's SID in Windows

I need to get the string format SID of the logged-on user. I already have the username and am trying to use LookupAccountName to get the SID. This works partly - I do get a SID but it is only a partial match to the user's actual SID.
I do not want the SID of the process owner as the process may be elevated (impersonating), but rather I want the SID of the user who is logged on where the process is running.
The code needs to work with non-elevated privileges.
This is my code so far
LPCTSTR wszAccName = TEXT("hardcoded username for testing");
LPTSTR wszDomainName = (LPTSTR)GlobalAlloc(GPTR, sizeof(TCHAR) * 1024);
DWORD cchDomainName = 1024;
SID_NAME_USE eSidType;
SID sid;
DWORD cbSid = 1024;
if (!LookupAccountName(NULL, wszAccName, &sid, &cbSid, wszDomainName, &cchDomainName, &eSidType)) {
return GetLastError();
}
if (!ConvertSidToStringSid(&sid, &pszSidBuffer)) {
return GetLastError();
}
This yields a SID like "S-1-5-21-1-1234567890-9-1000"
But the user's actual SID is like "S-1-5-21-3214321539-1234567890-2233445522-1000"
(as per the process owner and the registry key under HKEY_USERS).
Note how the SIDs are the same except for the 5th and 7th components, which are only 1 digit each but should be longer.
How do I get the user's actual/complete SID?
Also, I'm a total C/C++ newbie (and the code above is not production quality at all). And I'm using /NODEFAULTLIB in order to avoid linking VC runtimes. Sorry about that.
Your code doesn't provide a properly-sized buffer for the SID returned by LookupAccountName(). This results in stack corruption and undefined behaviour, which might conceivably explain why you're not getting the SID you were expecting. (Although I rather suspect that you're actually passing in the wrong username, or an improperly formatted username.)
Anyway, to fix the most obvious problem, the code should look more like this:
#include <Windows.h>
#include <Sddl.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
LPCTSTR wszAccName = TEXT("domainname\\username");
LPTSTR wszDomainName = (LPTSTR)GlobalAlloc(GPTR, sizeof(TCHAR) * 1024);
DWORD cchDomainName = 1024;
SID_NAME_USE eSidType;
LPTSTR sidstring;
char sid_buffer[1024];
DWORD cbSid = 1024;
SID * sid = (SID *)sid_buffer;
if (!LookupAccountName(NULL, wszAccName, sid_buffer, &cbSid, wszDomainName, &cchDomainName, &eSidType)) {
return GetLastError();
}
if (!ConvertSidToStringSid(sid, &sidstring)) {
return GetLastError();
}
printf("%ws\n", sidstring);
return 0;
}
That's still not the correct way to do it, of course; you are supposed to call LookupAccountName() twice, once to determine the buffer length and then a second time to retrieve the actual information. But it demonstrates what you've done wrong, and is good enough for testing purposes.

Error 12006 in WinHttpCrackUrl

I'm trying to build an address from a variable. So I can pass it to WinHttpOpenRequest.
char *uNameAddr = (char*) ExeBaseAddress + 0x34F01C;
printf("%s \n", uNameAddr);
string url = "http://xxxx.xxxx.com/xxxx/?u=";
string username = uNameAddr;
string combine = url + username;
cout << combine << endl;
//http://xxxx.xxxx.com/xxxx/?u=MyUsername <--
URL_COMPONENTS urlComp;
LPCWSTR pwszUrl1 = (LPCWSTR)combine.c_str();
DWORD dwUrlLen = 0;
Then I have to pass it here:
hRequest = WinHttpOpenRequest( hConnect, L"GET", urlComp.lpszUrlPath,
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
0);
urlComp.lpszUrlPath should be http://xxxx.xxxx.com/xxxx/?u=MyUsername
Any advice? My application crashes when it gets to process that part.
ERROR
12006 ERROR_INTERNET_UNRECOGNIZED_SCHEME
The URL scheme could not be recognized or is not supported.
LPCWSTR pwszUrl1 = (LPCWSTR)combine.c_str();
std::string::c_str returns const char *. LPCWSTR is const wchar_t *.
Casting to LPCWSTR is lying to the compiler and yourself, what combine.c_str() returns is not a pointer to a wide-character string.
You'll likely have better success with std::wstring, which represents wide-character strings.
Consider reading Unicode in the Windows API for more information.

C++ Get Program files dir, append extra path and execute

I'm trying to write a few simple lines of code that will get the 'Program Files' dir path on both XP and Vista/7 (on vista/7 I need the path to the x86 folder), add some extra path to an application and execute it.
This is what I have so far, but it's not executing the external program, not giving an error as well..
wchar_t localAppData[MAX_PATH];
STARTUPINFO sInfo;
PROCESS_INFORMATION pInfo;
SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, 0, NULL, localAppData);
std::wstringstream ss;
ss << localAppData << L"/MyApp/MyExe.exe";
LPCWSTR str = ss.str().c_str();
CreateProcess(str, NULL,NULL, NULL,FALSE,NULL,NULL,NULL,&sInfo,&pInfo);
return str;
I've updated my code to this according to hmjd's suggestion:
wchar_t localAppData[MAX_PATH];
STARTUPINFO sInfo = { sizeof(STARTUPINFO), NULL, L"winsta0\\default" };
PROCESS_INFORMATION pInfo;
SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, 0, NULL, localAppData);
std::wstringstream ss;
ss << localAppData << L"/PacificPoker/bin/888poker.exe";
std::wstring ss_str = ss.str();
wchar_t* path = new wchar_t[ss_str.length() + 1]();
std::copy(ss_str.begin(), ss_str.end(), path);
CreateProcess(path, NULL,NULL, NULL,FALSE,NULL,NULL,NULL,&sInfo,&pInfo);
delete[] path;
return GetLastError();
Still getting '3' for GetLastError, but I can confirm that C:\Program Files\MyApp\MyExe.exe exists..
A few problems with the code:
sInfo is not initialised, you at least need to set the cb member
STARTUPINFO sInfo = { sizeof(STARTUPINFO), // 'cb'
NULL, // 'lpReserved'
L"winsta0\\default" };// 'lpDesktop'
See STARTUPINFO for more details.
the first argument to CreateProcess() should be non-const, but is being passed c_str() which would be a const if it was not a dangling pointer. The ss.str() method returns a std::string, and the c_str() is returning a pointer into that std::string but it is a temporary object and is destroyed at the end of the expression (the ;), making str a dangling pointer. Change to:
std::wstring ss_str = ss.str();
wchar_t* path = new wchar_t[ss_str.length() + 1]();
std::copy(ss_str.begin(), ss_str.end(), path);
CreateProcess(path, ...);
delete[] path;
Check return values of all your functions and query GetLastError() to determine failure reason.
You've probably tried this, but does localAppData get a valid string if you set the CSIDL to CSIDL_PROGRAM_FILES instead of CSIDL_PROGRAM_FILESX86?
If you're testing under XP, I don't know what CSIDL_PROGRAM_FILESX86 will return.

EnumProcessModulesEx fails returning error code 299 (ERROR_PARTIAL_COPY)

I am calling the function EnumProcessModulesEx and it fails. I running on a 64-bit machine. Here is the code below:
wchar_t* dest = new wchar_t[100];
int index = SendMessage(processes, LB_GETCURSEL, 0, 0);
SendMessage(processes, LB_GETTEXT, index, (LPARAM)dest);
HMODULE module;
unsigned long cbneeded;
EnableTokenPrivilege(hWnd, SE_DEBUG_NAME);
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, _wtoi(dest));
int errorcode = GetLastError();
BOOL ret = EnumProcessModulesEx(h, &module, sizeof module, &cbneeded, LIST_MODULES_ALL);
int err = GetLastError();
wchar_t* name = new wchar_t[MAX_PATH];
GetModuleBaseName(h, module, name, sizeof name);
MessageBox(hWnd, name, L"Process Name", 0);
delete dest;
delete name;
Most probably you are trying to open 32bit process from 64bit application or vice versa. You can only work with processes of the same kind.
BOOL ret = EnumProcessModulesEx(h, &module, sizeof module, &cbneeded, LIST_MODULES_ALL);
The 3rd argument is supposed to be the size of the array of HMODULES you pass in the 2nd argument. You only pass 1, not big enough. Note the lpcbNeeded, it tells you how large the array needs to be to not get the error.
If the target platform is x86, then you can try to change it to x64.
You can read the document: https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodules
If this function is called from a 32-bit application running on WOW64, it can only enumerate the modules of a 32-bit process. If the process is a 64-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299).
Well, what does GetLastError return? EDIT: my bad, I failed hard..
Do error-checking and make sure it's not SendMessage, EnableTokenPrivilege, or OpenProcess that's giving you the error.