Archive

Posts Tagged ‘API’

Why you should develop with UNICODE?

August 14th, 2009 Sarath Comments

Most of the programmers like, have started coding with non-UNICODE character set. In schools, university it really doesn’t matter. What we focus on is the implementation or solution for a particular problem and thus we learn how to program. But things are a bit different when we comes to serious software development. There are few reasons to develop with UNICODE.

1. The new generation operating systems are distributed all over the world with different local language support like Chinese, Japanese, etc. and natively supports UNICODE. All the operating system interfaces are designed with UNICODE.
2. It allows to easily localize our application. Single binary can contain support for multiple languages.
3. In the performance point of view UNICODE is better than using ANSI interface. Because it’s required ANSI/MBCS to UNICODE conversion before calling system API. The conversion cost and temporary buffers will be an overhead. Also it ensures that we can use all Operating system interfaces. Some APIs only supports UNICODE interfaces only.
4. COM and .NET Framework requires UNICODE strings. So using UNICODE ensures smooth interoperability/integration with these frameworks.
Is there anything additional? Please post as comments.
Categories: Tips, windows Tags: , ,

Why CreateProcess commandline parameter should not be read-only memory?

June 5th, 2009 Sarath Comments

In the Book, Windows Via C/C++ Jeffrey Richter mentioned about the peculiarity of command line parameter of CreateProcess function.Normally for most of the Windows API, the input parameters are constant. But for CreateProcess, we’ve to pass the a non const string argument as command line parameter because internally the API modifying the input parameter and the the original data passed will be restored back to its original form, when the API call returns.

Let’s a dig a bit more.
The CreateProcess API takes the following form

[sourcecode language='cpp']
BOOL WINAPI CreateProcess(
__in_opt LPCTSTR lpApplicationName,
__inout_opt LPTSTR lpCommandLine,
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in_opt LPVOID lpEnvironment,
__in_opt LPCTSTR lpCurrentDirectory,
__in LPSTARTUPINFO lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);
[/sourcecode]

lpCommandLine parameter of the API is actually specified in LPTSTR which is defined as non-const TCHAR pointer. Effectively we’re not getting anything back from the API but still we’ve to pass a writable memory location. Otherwise there’s a chance to face an access violation as the API tries to modify the passing pointer.

For e.g

[sourcecode language='cpp']
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcess( NULL, _T(“NOTEPAD”), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
[/sourcecode]

The above call makes an access violation as the Microsoft C/C++ compiler placing the constant strings in the read only memory. If you use old version of a Microsoft compiler you may not face this access violation as the constant data is stored at read/write memory location.

The best thing we can do is to copy the string to a temporary buffer and pass to the API. We can hope that Microsoft may fix this issue in their future release.

CreateProcess is actually defined as
[sourcecode language='cpp']
#ifdef _UNICODE
#define CreateProcess CreateProcessW
#else
#define CreateProcess CreateProcessA
#endif
[/sourcecode]

If UNICODE is not defined in your project, the API may call ANSI version (CreateProcessA) function which is actually a wrapper function. Inside ANSI version of the most of the APIs, temporary string buffers are defined and the values are converted from ANSI to UNICODE. These string buffers are passed to the UNICODE version of the API which is actually doing the task(remember that Windows is a UNICODE Operating System). So that access violation may not occur for non-unicode applications.

We can solve this problem as follows

[sourcecode language='cpp']
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
TCHAR cmdline[] = _T( “NOTEPAD”);
CreateProcess( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
[/sourcecode]

Okay we’ve solved the problem. In his recent blog post, Raymond Chen has explained the some more interesting stuff on the same story.

Basically, somebody back in the 1980’s wanted to avoid allocating memory. (Another way of interpreting this is that somebody tried to be a bit too clever.)

The CreateProcess temporarily modifies the string you pass as the lpCommandLine in its attempt to figure out where the program name ends and the command line arguments begin. Now, it could have made a copy of the string and made its temporary modifications to the copy, but hey, if you modify the input string directly, then you save yourself an expensive memory allocation operation. Back in the old days, people worried about avoiding memory allocations, so this class of micro-optimization is the sort of thing people worried about as a matter of course. Of course, nowadays, it seems rather antiquated.

Now, there may also be good technical reasons (as opposed to merely performance considerations) for avoiding allocating memory on the heap. When a program crashes, the just in time debugger is launched with the CreateProcess function, and you don’t want to allocate memory on the heap if the reason the program crashed is that the heap is corrupted. Otherwise, you can get yourself into a recursive crash loop: While trying to launch the debugger, you crash, which means you try to launch the debugger to debug the new crash, which again crashes, and so on. The original authors of the CreateProcess function were careful to avoid allocating memory off the heap, so that in the case the function is being asked to launch the debugger, it won’t get waylaid by a corrupted heap.

Whether these concerns are still valid today I am not sure, but it was those concerns that influenced the original design and therefore the interface.

Categories: C++, Code, Tips, windows Tags: , , , ,

How to verify the embedded signature of a Windows PE file?

May 29th, 2009 Sarath Comments

In this post, I’m introducing the API which can be used to verify the signature of a Portable Executable (PE) file under windows. The applications like Process Explorer allows to verify the signature of the executables.

We can do the same thing using it using WinVerifyTrust. MSDN has a samplesnippet on the usage of this API. Let me put the same snippet (with some small modifications).

See the snippet list. It’s necessary to use Wide Character string(UNICODE) path to the file to use this function.

[sourcecode language='cpp']
BOOLVerifyEmbeddedSignature(LPCWSTR pwszSourceFile)
{
LONG lStatus;
DWORD dwLastError;

BOOL bRet = FALSE;

WINTRUST_FILE_INFO FileData;
memset(&FileData, 0, sizeof(FileData));
FileData.cbStruct = sizeof(WINTRUST_FILE_INFO);
FileData.pcwszFilePath = pwszSourceFile;
FileData.hFile = NULL;
FileData.pgKnownSubject = NULL;

GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
WINTRUST_DATA WinTrustData;

// Initialize the WinVerifyTrust input data structure.
// Default all fields to 0.
memset(&WinTrustData, 0, sizeof(WinTrustData));
WinTrustData.cbStruct = sizeof(WinTrustData);

WinTrustData.pPolicyCallbackData = NULL;
WinTrustData.pSIPClientData = NULL;
WinTrustData.dwUIChoice = WTD_UI_NONE;
WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
// Verify an embedded signature on a file.
WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
WinTrustData.dwStateAction = 0;
WinTrustData.hWVTStateData = NULL;
WinTrustData.pwszURLReference = NULL;

// Default.
WinTrustData.dwProvFlags = WTD_SAFER_FLAG;

// This is not applicable if there is no UI because it changes
// the UI to accommodate running applications instead of
// installing applications.
WinTrustData.dwUIContext = 0;

// Set pFile.
WinTrustData.pFile = &FileData;

// WinVerifyTrust verifies signatures as specified by the GUID
// and Wintrust_Data.
lStatus = WinVerifyTrust( NULL, &WVTPolicyGUID, &WinTrustData);

switch (lStatus)
{
case ERROR_SUCCESS:
{
CString strMessage;
strMessage.Format( _T( “The file \”%s\” is signed and the signature was verified.\n”),
pwszSourceFile);
AfxMessageBox( strMessage );
bRet = TRUE;
break;
}

case TRUST_E_NOSIGNATURE:
// The file was not signed or had a signature
// that was not valid.

// Get the reason for no signature.
dwLastError = GetLastError();
if (TRUST_E_NOSIGNATURE == dwLastError ||
TRUST_E_SUBJECT_FORM_UNKNOWN == dwLastError ||
TRUST_E_PROVIDER_UNKNOWN == dwLastError)
{
CString strMessage;
// The file was not signed.
strMessage.Format( _T( “The file \”%s\” is not signed.\n”), pwszSourceFile);
AfxMessageBox( strMessage );
}
else
{
// The signature was not valid or there was an error
// opening the file.
CString strMessage;

strMessage.Format( _T( “An unknown error occurred trying to ”
L”verify the signature of the \”%s\” file.\n”),
pwszSourceFile);
AfxMessageBox(strMessage);
}

break;

case TRUST_E_EXPLICIT_DISTRUST:
// The hash that represents the subject or the publisher
// is not allowed by the admin or user.
AfxMessageBox(L”The signature is present, but specifically disallowed.\n”);
break;

case TRUST_E_SUBJECT_NOT_TRUSTED:
// The user clicked “No” when asked to install and run.
AfxMessageBox( _T( “The signature is present, but not trusted.\n”));
break;

case CRYPT_E_SECURITY_SETTINGS:
/*
The hash that represents the subject or the publisher
was not explicitly trusted by the admin and the
admin policy has disabled user trust. No signature,
publisher or time stamp errors.
*/
MessageBoxW(L”CRYPT_E_SECURITY_SETTINGS – The hash ”
L”representing the subject or the publisher wasn’t ”
L”explicitly trusted by the admin and admin policy ”
L”has disabled user trust. No signature, publisher ”
L”or timestamp errors.\n”);
break;

default:
// The UI was disabled in dwUIChoice or the admin policy
// has disabled user trust. lStatus contains the
// publisher or time stamp chain error.
{
CString strMessage;
strMessage.Format( _T( “Error is: 0x%x.\n”), lStatus );
AfxMessageBox( strMessage );
break;
}
}
return bRet;
}
[/sourcecode]