ChangeServiceConfig2 using GetProcAddress to support multiple version of windows - c++

I'm using ChangeServiceConfig2 API of windows to change the service description. Since the same api is not supported in windows 98, ME I have used LoadLibraray and GetProcAddress to prevent static linking of the API in the exe. Please refer the code for more details:
typedef BOOL (*ChgSvcDesc) (SC_HANDLE hService, DWORD dwInfoLevel, LPVOID lpInfo);
eBool ServiceConfigNT::Install(IN tServiceDesc * pServiceDesc){
SC_HANDLE hservice;
SC_HANDLE hservicemgr;
SERVICE_DESCRIPTION desc;
ULong starttype;
HMODULE hmod;
ChgSvcDesc fpsvcdesc;
// Opens the Service Control Manager
hservicemgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(!hservicemgr){
vPrepareError(_TEXT("Failed to open service control manager!!"));
goto err;
}
// Set start method of service.
starttype = (pServiceDesc->uAutoStart == TRUE)? SERVICE_AUTO_START : SERVICE_DEMAND_START;
// Create the service
hservice = CreateService(hservicemgr, vServiceName, pServiceDesc->uDisplayName, SERVICE_ALL_ACCESS,
pServiceDesc->uServiceType, starttype, SERVICE_ERROR_NORMAL,pServiceDesc->uExePath,
NULL, NULL, NULL, NULL, NULL);
if(!hservice) {
vPrepareError(_TEXT("Failed to create service.!!"));
goto err;
}
// Set the description string
if(pServiceDesc->uServiceDescription && *pServiceDesc->uServiceDescription) {
desc.lpDescription = pServiceDesc->uServiceDescription;
// This cannot be executed since it is not supported in Win98 and ME OS
//(Void)ChangeServiceConfig2 (hservice, SERVICE_CONFIG_DESCRIPTION, &desc);
hmod = LoadLibrary(_TEXT("Advapi32.dll"));
if(hmod) {
// _UNICODE macro is set, hence im using the "W" version of the api
fpsvcdesc = (ChgSvcDesc)GetProcAddress(hmod, "ChangeServiceConfig2W");
if(fpsvcdesc)
// On execution of the below statement, I get the error handle is invalid
fpsvcdesc(hservice, SERVICE_CONFIG_DESCRIPTION, &desc);
}
CloseServiceHandle(hservice);
CloseServiceHandle(hservicemgr);
return TRUE;
err:
if(hservicemgr)
CloseServiceHandle(hservicemgr);
return FALSE;
}
I debugged the code many times to find out why I am getting handle is invalid error ? On calling the API directly the description of service is changing but using the function pointer it gives the error.
I think that the API is writing something to the service handle of the SCM, but I have no clues as to why ?
Can somebody help me with this ?

Your function pointer is declared with no calling convention specified. The default calling convention is __cdecl. But Windows API functions are __stdcall. You need to add the calling convention to your function pointer type.
typedef BOOL (__stdcall *ChgSvcDesc) (SC_HANDLE hService,
DWORD dwInfoLevel, LPVOID lpInfo);

Related

Running programs using RtlCreateUserProcess only works occasionally

Disclaimer: This questions seems to get downvoted because I should use the normal Win32 API (CreateProcess, ShellExecute). I know about these APIs and I'm aware that RtlCreateUserProcess is not supposed to be called directly. However, the native API is a very relevant topic regarding security, that's why I am researching it.
I'm trying to run programs on Windows using the function RtlCreateUserProcess, exported from ntdll.dll. My code works to run calc.exe, however, after trying to run notepad.exe, I receive an error message that reads The ordinal 345 could not be located in dynamic link library "C:\Windows\SysWOW64\notepad.exe". When trying to run other programs it displays various similar messages, always related to some ordinals or DLLs missing.
My example code looks like this:
#include <windows.h>
#include <iostream>
#include <winternl.h>
typedef struct _SECTION_IMAGE_INFORMATION {
PVOID EntryPoint;
ULONG StackZeroBits;
ULONG StackReserved;
ULONG StackCommit;
ULONG ImageSubsystem;
WORD SubSystemVersionLow;
WORD SubSystemVersionHigh;
ULONG Unknown1;
ULONG ImageCharacteristics;
ULONG ImageMachineType;
ULONG Unknown2[3];
} SECTION_IMAGE_INFORMATION, * PSECTION_IMAGE_INFORMATION;
typedef struct _RTL_USER_PROCESS_INFORMATION {
ULONG Size;
HANDLE ProcessHandle;
HANDLE ThreadHandle;
CLIENT_ID ClientId;
SECTION_IMAGE_INFORMATION ImageInformation;
} RTL_USER_PROCESS_INFORMATION, * PRTL_USER_PROCESS_INFORMATION;
typedef VOID(NTAPI* Func1)(PUNICODE_STRING DestinationString, __drv_aliasesMem PCWSTR SourceString);
typedef NTSTATUS(NTAPI* Func2)(OUT PRTL_USER_PROCESS_PARAMETERS* pProcessParameters, IN PUNICODE_STRING ImagePathName, IN PUNICODE_STRING DllPath OPTIONAL, IN PUNICODE_STRING CurrentDirectory OPTIONAL, IN PUNICODE_STRING CommandLine OPTIONAL, IN PVOID Environment OPTIONAL, IN PUNICODE_STRING WindowTitle OPTIONAL, IN PUNICODE_STRING DesktopInfo OPTIONAL, IN PUNICODE_STRING ShellInfo OPTIONAL, IN PUNICODE_STRING RuntimeData OPTIONAL);
typedef NTSTATUS(NTAPI* Func3)(PUNICODE_STRING NtImagePathName, ULONG Attributes, PRTL_USER_PROCESS_PARAMETERS ProcessParameters, PSECURITY_DESCRIPTOR ProcessSecurityDescriptor, PSECURITY_DESCRIPTOR ThreadSecurityDescriptor, HANDLE ParentProcess, BOOLEAN InheritHandles, HANDLE DebugPort, HANDLE ExceptionPort, PRTL_USER_PROCESS_INFORMATION ProcessInformation);
int main()
{
UNICODE_STRING str;
PRTL_USER_PROCESS_PARAMETERS processparameters;
RTL_USER_PROCESS_INFORMATION processinformation = { 0 };
Func1 RtlInitUnicodeString = (Func1)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlInitUnicodeString");
Func2 RtlCreateProcessParameters = (Func2)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlCreateProcessParameters");
Func3 RtlCreateUserProcess = (Func3)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlCreateUserProcess");
RtlInitUnicodeString(&str, L"\\??\\C:\\Windows\\SysWOW64\\notepad.exe"); //Starting calc.exe works, notepad.exe does not.
RtlCreateProcessParameters(&processparameters, &str, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
NTSTATUS works = RtlCreateUserProcess(&str, OBJ_CASE_INSENSITIVE, processparameters, NULL, NULL, NULL, FALSE, NULL, NULL, &processinformation);
if (NT_SUCCESS(works)) {
ResumeThread(processinformation.ThreadHandle);
//Started application crashes at this point + the error message gets shown
}
else {
std::cout << "Failed" << std::endl;
}
return 0;
}
Unfortunately, there is not much information available about using this function, so I would appreciate any answers on how to use this function correctly.
CreateProcess after create new process do much more job, in particular it create activation context for new process based on exe manifest (BasepConstructSxsCreateProcessMessage + CsrClientCallServer) as result new process have initial activation context, stored in PEB (SystemDefaultActivationContextData and ActivationContextData) but in process created with pure call to RtlCreateUserProcess this fields is empty (0). as result your process loaded ComCtl32.dll from system32 (version 5.82 ) and notepad with activation context - 6+ version.
The ordinal 345 could not be located in dynamic link library
really in ComCtl32.DLL pre 6 version (5.82). 345 - this is TaskDialogIndirect api which exist only in ComCtl32.DLL version 6+. but your process load 5.82.. - calling TaskDialogIndirect loader says ordinal 345 not found
so CreateProcess not a thin shell over RtlCreateUserProcess or NtCreateUserProcess, but big and complex api. at it functional very hard if possible at all implement direct

Get machine name from registry using RegQueryValueEx

I am trying to do an application which shows machine name of the PC fetch from registry. It has to run in 64 bit window 7 machine.
But I can only manage to output the system error message.
In below code,
I always get value of value1str (using RegOpenKeyEx method) => as 0 (which is ERROR_SUCCESS)
and value2str (using RegQueryValueEx method) => as 2 (which is ERROR_FILE_NOT_FOUND)
Anyone knows how to display the real machine name?
Please help!
#define KEY_WOW64_64KEY (0x0100)
#include <iostream>
#include <string>
BEGIN_MESSAGE_MAP(CPOConLogApp, CWinApp)
END_MESSAGE_MAP()
CPOConLogApp::CPOConLogApp()
{
int value1;
int value2;
HKEY root = NULL;
CString value1Str,value2Str;
value1=RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName"), NULL, KEY_READ|KEY_WOW64_64KEY, &root);
value1Str.Format("%d",value1);
MessageBoxA ( NULL, value1Str, "Test", MB_OK );
LPBYTE data = NULL;
DWORD dwType;
DWORD dwSize;
data = new BYTE[dwType];
value2=RegQueryValueEx(HKEY_LOCAL_MACHINE,TEXT("Computer Name"), NULL, &dwType, data, &dwSize);
value2Str.Format("%d",value2);
MessageBoxA (NULL, value2Str , "Test", MB_OK );
}
Alternative solution:
Instead of trying to find where is the key in the Registry and how to read it, you can just rely on the API Microsoft provide.
To get the Computer NetBIOS name (initialized from registry at system startup) use GetComputerName like below.
#include <windows.h>
int main()
{
char buf[1024];
DWORD dwCompNameLen = 1024;
if (0 != GetComputerName(buf, &dwCompNameLen)) {
printf("name %s\n", buf);
}
return 0;
}
You can read the computer name from the below mentioned registry key,
System\CurrentControlSet\Control\ComputerName\ComputerName
I found out why always ERROR_FILE_NOT_FOUND value. I suppose to put last parameter of RegOpenKeyEx to the first parameter in RegQueryValueEx. It should be like this.
value2=RegQueryValueEx(root,TEXT("Computer Name"), NULL, &dwType, data, &dwSize);
If you want prompts the value of the registry, computer name in this case, use the below code.
value.Format("%s",pszBuffer);
MessageBoxA (NULL, value , "Test", MB_OK );

IAT Hooking for testings

I am trying to hook a function to cmd.exe process
the dll is injected just fine the problem is i can't get the cmd.exe to call my function
when im trying to enter the word "dir" on the command prompt it's showing me the same results instade of changing the first name to 'dan'
what am i doing wrong?
HANDLE WINAPI newFindFirstFileA(__in LPCTSTR lpFileName, __out LPWIN32_FIND_DATA lpFindFileData)
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind = FindFirstFile(lpFileName, &FindFileData);
*FindFileData.cFileName = L'Dan';
lpFindFileData = &FindFileData;
return hFind;
}
BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
DWORD reason /* Reason this function is being called. */ ,
LPVOID reserved /* Not used. */ )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
MessageBox(NULL,L"DLL Was injected!", L"Message" ,NULL);
/* Hooking function */
DWORD* dw = (DWORD*)GetProcAddress( GetModuleHandleA("kernel32.dll"), "FindFirstFileA" );
*dw = (DWORD)newFindFirstFileA;
break;
}
/* Returns TRUE on success, FALSE on failure */
return TRUE;
}
GetProcAddress does not return the pointer to IAT entry. Instead, it returns the location of the actual function. Thus, *dw = (DWORD) newFindFirstFileA would overwrite the prolog of the FindFirstFileA function, which would be disastrous. Refer to this article for detailed explanation for hooking an API

Calling a COM dll from c++, "Class Not Registered"

I have created a COM dll in Microsoft Visual Basic 2008. I am trying to call this dll from a C++ project. In the C++ I used "#import U:\path...\MyComDll.tlb" I then used the following code to the DisplayMessage() method.
FB::variant CmdAccessAPI::filePSV(std::string file)
{
CoInitialize(NULL);
try
{
_MyComClassPtr spIMyComClass;
HRESULT hr = spIMyComClass.CreateInstance(__uuidof(_MyComClass));
if (FAILED(hr)) throw _com_error(hr);
spIMyComClass->DisplayMessage();
}
catch (std::exception& e)
{
CString strMsg(e.what());
MessageBox(NULL, strMsg, L"Error", MB_OK);
}
catch (_com_error& e)
{
CString strMsg;
strMsg = (TCHAR*) e.Description();
strMsg += _T("\n");
strMsg += (TCHAR*) e.ErrorMessage();
MessageBox(NULL, strMsg, L"COM Error", MB_OK);
}
CoUninitialize();
return "test";
}
When I call this function I get a Class Not Registered error. I have tried to register the dll using regsvr32 and I get the message "MyComDll.dll was loaded, but the DLLREgeisterServer entry point was not found. This file can not be registered."
How do I register the class and get this to work?
Try registering it using admin privileges,
Right click on the Command prompt and choose run as administrator, and give the systems 32 path.
Then use regsvr32 xyz.dll
If you can't register it, there are two possibilities
You are missing a dependent library. Download dependency walker and see what's missing. Some of the ones that are marked missing are red herrings (ieshims.dll for example), but one of them may be yours
Something went way off the rails in your COM setup. You can debug your dll as its being registered and dig into the ATL code where its failing.
You need to use regsvr32 to register the DLL, as you suspect.
However, the error its giving suggests that either the DLL doesn't have the stub included (and so cannot register itself) or you're trying to register the library, not the stub.
Make sure your VS project and the code is set up to include the proxy/stub functions in your DLL, or make sure you register the proxy DLL.
**include the below code** and export these functions with .def file
wchar_t *convertCharArrayToLPCWSTR(const char* charArray)
{
wchar_t* wString=new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
return wString;
}
BOOL Register( HKEY mainKey,const char *subKey,LPCTSTR val_name, DWORD dwType,char * chardata,DWORD dwDataSize)
{
HKEY hk;
if (ERROR_SUCCESS != RegCreateKey(mainKey,convertCharArrayToLPCWSTR(subKey),&hk) )
return FALSE;
LPCTSTR data=convertCharArrayToLPCWSTR(chardata);
if (ERROR_SUCCESS != RegSetValueEx(hk,val_name,0,dwType,(CONST BYTE *)data,2*dwDataSize))
return FALSE;
if (ERROR_SUCCESS != RegCloseKey(hk))
return FALSE;
return TRUE;
}
HRESULT __stdcall DllRegisterServer(void)
{
WCHAR *lpwszClsid;
char szBuff[MAX_PATH]="new multiplication Algorithm";
char szClsid[MAX_PATH]="", szInproc[MAX_PATH]="",szProgId[MAX_PATH];
char szDescriptionVal[256]="";
StringFromCLSID(CLSID_MultiplicationObject,&lpwszClsid);
sprintf(szClsid,"%S",lpwszClsid);
sprintf(szInproc,"%s\\%s\\%s","clsid",szClsid,"InprocServer32");
sprintf(szProgId,"%s\\%s\\%s","clsid",szClsid,"ProgId");
sprintf(szDescriptionVal,"%s\\%s","clsid",szClsid);
Register (HKEY_CLASSES_ROOT,szDescriptionVal,NULL,REG_SZ,szBuff,strlen(szBuff));
//InprocServer32
GetModuleFileNameA(g_hModule,szBuff,sizeof(szBuff));
Register (HKEY_CLASSES_ROOT,szInproc,NULL,REG_SZ,szBuff,strlen((szBuff)));
//ProgId
strcpy(szBuff,multiplicationObjProgId);
Register (HKEY_CLASSES_ROOT,szProgId,NULL,REG_SZ,szBuff,strlen(szBuff));
return 1;
}
HRESULT __stdcall DllUnregisterServer(void)
{
WCHAR *lpwszClsid;
char szBuff[MAX_PATH]="new multiplication Algorithm";
char szClsid[MAX_PATH]="", szInproc[MAX_PATH]="",szProgId[MAX_PATH];
char szDescriptionVal[256]="";
StringFromCLSID(CLSID_MultiplicationObject,&lpwszClsid);
sprintf(szClsid,"%S",lpwszClsid);
sprintf(szInproc,"%s\\%s\\%s","clsid",szClsid,"InprocServer32");
sprintf(szProgId,"%s\\%s\\%s","clsid",szClsid,"ProgId");
sprintf(szDescriptionVal,"%s\\%s","clsid",szClsid);
RegDeleteKey(HKEY_CLASSES_ROOT,convertCharArrayToLPCWSTR(szInproc));
RegDeleteKey(HKEY_CLASSES_ROOT,convertCharArrayToLPCWSTR(szProgId));
RegDeleteKey(HKEY_CLASSES_ROOT,convertCharArrayToLPCWSTR(szDescriptionVal));
return 1;
}
This kind of dependency problem can happen when there is a mismatch in vendor architecture.
For example, you may have registered the 32bit DLL but your program is 64bit or vice-versa.

Create a new windows registry key using c++

I'm trying to create a new registry key in the windows registry using C++. Here is the code I have so far:
HKEY hKey;
LPCTSTR sk = TEXT("SOFTWARE\\OtherTestSoftware");
LONG openRes = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
sk,
0,
NULL,
REG_OPTION_BACKUP_RESTORE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL);
if (openRes==ERROR_SUCCESS) {
printf("Success creating key.");
} else {
printf("Error creating key.");
}
LPCTSTR value = TEXT("OtherTestSoftwareKey");
LPCTSTR data = "OtherTestData\0";
LONG setRes = RegSetValueEx (hKey, value, 0, REG_SZ, (LPBYTE)data, strlen(data)+1);
if (setRes == ERROR_SUCCESS) {
printf("Success writing to Registry.");
} else {
printf("Error writing to Registry.");
}
//RegDeleteKey(hKey, sk);
LONG closeOut = RegCloseKey(hKey);
if (closeOut == ERROR_SUCCESS) {
printf("Success closing key.");
} else {
printf("Error closing key.");
}
I'm able to successfully open an existing key using a very similar code snippet (basically replace RegCreateKeyEx with RegOpenKeyEx). I would imagine that one or more of the arguments I'm passing into RegCreateKeyEx is causing the trouble. I'm honestly not sure where things might be getting fouled up since all of the error codes i've trapped show success. For reference, here is the function signature for RegCreateKeyEx:
/*
* LONG WINAPI RegCreateKeyEx(
__in HKEY hKey,
__in LPCTSTR lpSubKey,
__reserved DWORD Reserved,
__in_opt LPTSTR lpClass,
__in DWORD dwOptions,
__in REGSAM samDesired,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__out PHKEY phkResult,
__out_opt LPDWORD lpdwDisposition
);
*/
Any thoughts would be great!
thanks,
brian
I've been compiling my own personal Function Library for years. One part of this deals entirely with registry access, see the CreateRegistryKey function the Registry.Cpp file.
If you are interested, you can grab the entire library here.
As already mentioned, you've specified the REG_OPTION_BACKUP_RESTORE option in the call to RegCreateKeyEx, which means that you're opening the key in order to perform a backup or restore. Ordinarily, you would use REG_OPTION_NON_VOLATILE instead.
What operating system are you running? In Windows 2000/XP, the HKEY_LOCAL_MACHINE registry hive is not writeable by non-administrator users, so RegCreateKeyEx will fail with an access denied error (error 5). This also applies to Vista, if your application has a requestedExecutionLevel entry in its manifest. If you're running Vista, and your application doesn't specify a requestedExecutionLevel (or if it doesn't have a manifest at all), access to HKEY_LOCAL_MACHINE will be virtualised, so RegCreateKeyEx should succeed. See Registry Virtualization in Windows Vista in MSDN for more details.
There are some more problems with the code you've posted, which will only become apparent if you compile your project with UNICODE defined. This line:
LPCTSTR data = "OtherTestData\0";
should be
LPCTSTR data = TEXT("OtherTestData\0");
and this line:
LONG setRes = RegSetValueEx(hKey, value, 0, REG_SZ,
(LPBYTE)data, _tcslen(data)+1);
should be:
LONG setRes = RegSetValueEx(hKey, value, 0, REG_SZ,
(LPBYTE)data, (_tcslen(data)+1) * sizeof(TCHAR));
because the cbData parameter in RegSetValueEx is the length of the data in bytes, not characters.
I hope this helps!
The first clue is your use of REG_OPTION_BACKUP_RESTORE. You probably don't want to use that flag, as I believe it requires a special "backup" privilege that you need to enable beforehand. Normal applications won't want to do that.
Probably this is the reason why you can cannot create a new key, with your code.
These links might be of help.
http://www.codeguru.com/forum/archive/index.php/t-378884.html
http://www.codeguru.com/forum/archive/index.php/t-275250.html
As a sidenote, always try GetLastError() to get the error message.
I have not tested either of them.