what are the restrictions for writing plugins?

Started by MrManlyMan, December 12, 2009, 02:53:44 PM

Previous topic - Next topic

MrManlyMan

Hi,

  I'm trying to write a codec plugin in c.  I'm having trouble specifically with the Decode.  I've avoided any globals or constants and external references.  I'm pulling api calls through pLoadLibrary/pGetProcAddress.  Am I missing anything?  I'm trying to get values from the registry its somewhat working but I'm getting strange behavior after getting the first key.

Thanks.

Jeremy Collake

#1
Its hard to say what the problem is without seeing the code. If you would like to post your code here, publicly, then perhaps I or someone could tell you the problem.
Software Engineer. Bitsum LLC.

Jeremy Collake

#2
... it sounds like you've got the basic principle down, that your decoder must be able to stand-alone, contiguous, and not have external references. That's why I suggest posting the code, it will be easier than going through theoretical conditions. You can email it to me if it is private.
Software Engineer. Bitsum LLC.

MrManlyMan

Thanks so much for taking a look.  Here it is:

#include "stdafx.h"
#include "pec2codec_template.h"
#include "..\pec2codecsdk.h"
#include "Codec_0_EntryPoints.h"

/////////////////////////////////////////////////////////////////////////////////////
//
// GetCodecName
//
// Return the wide-characte rname of this CODEC.
//
//

static const char * stringtable[] =
{
"user32.dll",
"MessageBoxA",
"SOFTWARE\\Microsoft\\Cryptography",
"MachineGuid",
"SOFTWARE\\MyComputer\\MySoftware\\1.0",
"user",
"Advapi32.dll",
"RegOpenKeyExA",
"RegQueryValueExA",
"RegCloseKey",
"WTF",
"OMG"
};


DWORD WINAPI GetCodecName(PWCHAR pwszName, DWORD dwBufSize)
{
if(dwBufSize<=wcslen(CODEC_NAME))
{
if(pwszName)
{
*pwszName=NULL;
}
return wcslen(CODEC_NAME)+1;
}
else if(!dwBufSize)
{
return wcslen(CODEC_NAME)+1;
}
wcscpy(pwszName,CODEC_NAME);
return wcslen(pwszName);
}


DWORD WINAPI GetCodecAuthor(PWCHAR pwszAuthor, DWORD dwBufSize)
{
if(dwBufSize<=wcslen(CODEC_AUTHOR))
{
if(pwszAuthor)
{
*pwszAuthor=NULL;
}
return wcslen(CODEC_AUTHOR)+1;
}
else if(!dwBufSize)
{
return wcslen(CODEC_AUTHOR)+1;
}
wcscpy(pwszAuthor,CODEC_AUTHOR);
return wcslen(pwszAuthor);
}

#define CODEC_VERSION_MAJOR 1
#define CODEC_VERSION_MINOR 0
#define CODEC_VERSION (CODEC_VERSION_MAJOR*100)+CODEC_VERSION_MINOR

DWORD WINAPI GetCodecVersion(PDWORD pdwSDKVersion)
{
if(pdwSDKVersion)
{
*pdwSDKVersion=PEC2_CODEC_SDK_VERSION;
}
return CODEC_VERSION;
}

/////////////////////////////////////////////////////////////////////////////////////
//
//  Encode function
//
//  This codec simply copies the data from the source to the destination
//  and appends a flag. It actually expands the data, which is a perfectly
//  legal result no matter what the expansion size is. Of course, a compression
//  function would return a buffer smaller than the original (provided compression
//  succeeds).
//

DWORD WINAPI Encode( LPVOID lpvSource, DWORD dwLength, LPVOID lpvDest, DWORD *pdwDestSize, DWORD dwLevel, PFNCodecCallback Callback )
{
int nR;
PCODEC_0_HEADER pBlockHeader=(PCODEC_0_HEADER)lpvDest;

nR = sizeof(CODEC_0_HEADER) + dwLength;
//
// make sure destination buffer is big enough to handle our header
// expansion of the source data. If not, return PEC2_CODEC_ERROR_INSUFFICIENT_BUFFER
// so that the caller will allocate more and reinvoke.
//
if (*pdwDestSize<nR)
{
*pdwDestSize=nR;
return PEC2_CODEC_ERROR_INSUFFICIENT_BUFFER;
}

pBlockHeader->dwDecodedSize = dwLength;
pBlockHeader->dwSignature = CODEC_0_SIGNATURE;

int i;
for ( i=0; i<sizeof(stringtable)/sizeof(stringtable[0]); i++ )
{
strcpy( pBlockHeader->strings[i], stringtable[i] );
}

//
// copy source data to destination buffer
//
memcpy( (char*)(pBlockHeader+1),lpvSource,dwLength);

return nR;
}

typedef
int (*MessageBoxA_t)(   
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType);

typedef
LSTATUS
(*RegOpenKeyExA_t) (
    __in HKEY hKey,
    __in_opt LPCSTR lpSubKey,
    __in_opt DWORD ulOptions,
    __in REGSAM samDesired,
    __out PHKEY phkResult
    );

typedef
WINADVAPI
LSTATUS
(*RegQueryValueExA_t) (
    __in HKEY hKey,
    __in_opt LPCSTR lpValueName,
    __reserved LPDWORD lpReserved,
    __out_opt LPDWORD lpType,
    __out_bcount_part_opt(*lpcbData, *lpcbData) __out_data_source(REGISTRY) LPBYTE lpData,
    __inout_opt LPDWORD lpcbData
    );

typedef
WINADVAPI
LSTATUS
(*RegCloseKey_t) (
    __in HKEY hKey
    );


#define BUFFER_SIZE 8192

DWORD WINAPI Decode_Small(LPVOID lpvSource, LPVOID lpvDest, PEC2_DECODE_EXTRA * lpExtraData)
{
PCODEC_0_HEADER h = (PCODEC_0_HEADER)lpvSource;

//
// import functions
//
HMODULE user32_dll = lpExtraData->pLoadLibraryA( h->strings[0] );
MessageBoxA_t pMessageBoxA = (MessageBoxA_t)lpExtraData->pGetProcAddress( user32_dll, h->strings[1] );

HMODULE Advapi32_dll = lpExtraData->pLoadLibraryA( h->strings[6] );
RegOpenKeyExA_t pRegOpenKeyExA = (RegOpenKeyExA_t)lpExtraData->pGetProcAddress( Advapi32_dll, h->strings[7] );
RegQueryValueExA_t pRegQueryValueExA = (RegQueryValueExA_t)lpExtraData->pGetProcAddress( Advapi32_dll, h->strings[8] );
RegCloseKey_t pRegCloseKey = (RegCloseKey_t)lpExtraData->pGetProcAddress( Advapi32_dll, h->strings[9] );

//
// create buffer for machine, user, and product id
//
DWORD size = BUFFER_SIZE;
DWORD n = 0;
BYTE * buffer = (BYTE*)lpExtraData->pVirtualAlloc( NULL, size, MEM_COMMIT, PAGE_READWRITE );
if ( !buffer )
return -1;

HKEY hkey;

//
// retrieve machine id from registry
//
size = BUFFER_SIZE - n;
if ( pRegOpenKeyExA( HKEY_LOCAL_MACHINE, h->strings[2], 0, KEY_QUERY_VALUE, &hkey ) != ERROR_SUCCESS ) return -1;
if ( pRegQueryValueExA( hkey, h->strings[3], 0, NULL, buffer+n, &size ) != ERROR_SUCCESS ) return -1;
if ( pRegCloseKey( hkey ) != ERROR_SUCCESS ) return -1;
n += size;

//
// retrieve current user id from registry
//
size = BUFFER_SIZE - n;
if ( pRegOpenKeyExA( HKEY_LOCAL_MACHINE, h->strings[4], 0, KEY_QUERY_VALUE, &hkey ) != ERROR_SUCCESS ) return -1;
if ( pRegQueryValueExA( hkey, h->strings[5], 0, NULL, buffer+n, &size ) != ERROR_SUCCESS ) return -1;
if ( pRegCloseKey( hkey ) != ERROR_SUCCESS ) return -1;
n += size;

pMessageBoxA( NULL, (char*)buffer, h->strings[0], MB_OK );

return -1;
}

DWORD WINAPI GetDecodeSmallFuncSize()
{
unsigned char *pStart=(unsigned char *)&Decode_Small;
unsigned char *pEnd=(unsigned char *)&GetDecodeSmallFuncSize;
return (pEnd-pStart);
}



Jeremy Collake

#4
At a cursory glance, I see no glaring errors. So, its hard to say the problem without running it through a debugger. You appear to have obeyed all necessary constraints. There is the possibility of a registry handle leak in failure conditions, but that's not at all relevant, and this isn't final code or a college test, lol. It may be some implementation error in your code I'm not immediately seeing. I am out of time for now.

If you have the registered version of PECompact, you can use the pec2ldr_debug.dll loader host to help you more easily debug a compressed program. If you don't have it, maybe I can email it to you so you can trace through things in a debugger. You will just need to email me and tell me from what company you are coming from so I can ensure you are legit.

Email me at jeremy@bitsum.com ..



Software Engineer. Bitsum LLC.

Jeremy Collake

The user here reported that after switching to assembly, he had no problems. This suggest that the a possible problem was in the compiler settings. The compiler may have had a feature turned on that called out to a CRT function (i.e. buffer security check) from the decoder.
Software Engineer. Bitsum LLC.

safred

I ran into the same issues, calling system API in my codec DecodeSmall function would work a couple of times, and then crash. The problem got solved when I changed the "Calling Convention" option to "__stdcall (/Gz)" in Visual Studio's Project Property page -> Configuration Properties -> C/C++ -> Advanced.
Thought this might help.

Jeremy Collake

Yes, and this is something I should have made clear in the documentation, the calling convention MUST be stdcall, else the results could be anything from half-working to crashing all the time. This is the standard Windows  API calling convention (by and large) so it is implicit to some degree, but it is NOT the default C/C++ calling convention, so does need specifically declared in the function prototype OR project compiler configuration.
Software Engineer. Bitsum LLC.