How to extract Interface and Property details from NPAPI Windows plugin

 

In this post we will see how we can extract the interface/property details from the NPAPI plugin. Before moving further i have to warn you that there is no easy way to extract to all the information in automated fashion. Before going further in this topic, you should read my earlier post and links in that (https://hiddencodes.wordpress.com/2011/07/29/npapi-plugin-must-read/).

From here, i assume that you finished reading (and understood) at least 3 parts of 4 part tutorial. Ok lets start the journey.

To find the properties and interfaces we need to locate the following functions in the target’s scriptable object:

For Interfaces:

Invoke()

InvokeDefault()

HasMethod()

For Properties:

HasProperty()

GetProperty()

SetProperty()

I will use the npruntime NPAPI windows binary to locate the interfaces and properties. In the later post, i will do my work on finding these details for other NPAPI plugins.

As you know, required entry points for Windows NPAPI plugin:

NPError WINAPI NP_GetEntryPoints(NPPluginFuncs*)
NPError WINAPI NP_Initialize(NPNetscapeFuncs*)
NPError OSCALL NP_Shutdown()

Step 1:

First, we need to find the addresses of plugin(NPP_*) function’s . If you analyse the NP_GetEntryPoints() function then you can see there are lot of plugin functions are saved in this passed structure. See the image. (In the end of the post, i have given the link for IDC file that creates these structures/Enum for you in IDA Pro.)

image

(Note: Execute the IDC script attached to this post and select these instruction and press T , you will get a window to choose a register and structure. You have to choose “_NPPluginFuncs” structure.)

Make note of “NPP_GetValueProcPtr” value. You need to follow NPP_GetValue() to get the address of “Scriptable Object” (Functions in this object gets executed when you call the function from the Javascript).NPP_GetValue() is called by the browser to get various information about the plugin. One of that is , “scriptable Object”.Browser asks for “NPPVpluginScriptableNPObject” and plugin returns an instance of Scriptable Object.

     image

(Note: Browser calls this functions to get the Plugin’s name and description.)

You can see that, when browser asks for NPPVpluginScriptableNPObject, it returns the object.Call at 0x100135C5 returns the object of “Scriptable Object”. At this point, we don’t know what the function @ 0x10011104 does. Lets rename the function “sub_10011104” to “j_sub_100166A0”

Step 2:

At this point , we know the address of function that creates this scriptable object but we don’t exactly where it is created down the line. We know for sure that plugin should call NPN_CreateObject() function to create an object. So we need to find where plugin is calling the browsers NPN_CreateObject() function.To find this , we need to track the pointer that is passed to the NP_Initialize(). NP_Initialize() receives pointers to all browser functions that are used by plugin. If you analyse NP_Initialize() function, you can see how plugin saves various “browser functions” for its usage. What we are interested in is, NPN_CreateObject().

image

 

Pointer to browsers NPN_CreateObject() function is stored in NPN_CreateObject_ptr by the plugin.If you see the XREF of this pointer, you can find only few functions actually uses this.

image

 

One of this function is, sub_10012A90 , the plugin function that creates this scriptable object. Lets rename this function to “myplugincreateobject”.

image

This function is actually referenced by only one function “j_myplugincreateobject”. That is just a “jmp”.

Ok. Now we know two things.

1. Know the plugin function that creates the scriptable object.

2. Know the function that creates the object using NPN_CreateObject().

Step 3:

Now let’s keep following from the point we stopped at Step 1.

Call at 0x100135C5.

.text:100135C2 loc_100135C2: ; CODE XREF: NPP_GetValue+78j
.text:100135C2                  mov ecx, [ebp+var_14]
.text:100135C5                 call j_sub_100166A0
.text:100135CA                 mov ecx, [ebp+arg_8]
.text:100135CD                 mov [ecx], eax
.text:100135CF                  jmp short loc_100135DA

………………..

.text:10011104 j_sub_100166A0 proc near ; CODE XREF: NPP_GetValue+95p
.text:10011104 ; .text:10013910p
.text:10011104            jmp sub_100166A0
.text:10011104 j_sub_100166A0 endp

This function actually creates the object. That references the function we found through Step 2.

image

We reached the point, where it creates the object. Arguments to NPN_CreateObject() are instance and pointer to NPClass of “Scriptable Object”. If you trace backwards from that point , we can find that second argument to “j_myplugincreateobject” is pointer to NPClass of “Scriptable Object”. We will see how NPClass is created now.

NPClass for a “scriptable object” is created like this,

#define DECLARE_NPOBJECT_CLASS_WITH_BASE(_class, ctor) \
static NPClass s##_class##_NPClass = { \
             NP_CLASS_STRUCT_VERSION_CTOR, \ 
             ctor, \
             ScriptablePluginObjectBase::_Deallocate, \
             ScriptablePluginObjectBase::_Invalidate, \
             ScriptablePluginObjectBase::_HasMethod, \
             ScriptablePluginObjectBase::_Invoke, \
             ScriptablePluginObjectBase::_InvokeDefault, \
             ScriptablePluginObjectBase::_HasProperty, \
             ScriptablePluginObjectBase::_GetProperty, \
             ScriptablePluginObjectBase::_SetProperty, \
             ScriptablePluginObjectBase::_RemoveProperty, \
             ScriptablePluginObjectBase::_Enumerate, \
             ScriptablePluginObjectBase::_Construct \
}

So, the first function pointer is “allocate” function. That does allocation and initializes the object.

struct NPClass
{
      uint32_t structVersion;
      NPAllocateFunctionPtr allocate;
      NPDeallocateFunctionPtr deallocate;
      NPInvalidateFunctionPtr invalidate;
      NPHasMethodFunctionPtr hasMethod;
      NPInvokeFunctionPtr invoke;
      NPInvokeDefaultFunctionPtr invokeDefault;
      NPHasPropertyFunctionPtr hasProperty;
      NPGetPropertyFunctionPtr getProperty;
      NPSetPropertyFunctionPtr setProperty;
      NPRemovePropertyFunctionPtr removeProperty;
      NPEnumerationFunctionPtr enumerate;
      NPConstructFunctionPtr construct;
};

All we are interested is, allocate, function pointer. We can find the vtable from that.

image

sub_10014B70 is allocate() function.

image

Call 0x10014BDA initializes the object.

.text:10011217 sub_10011217 proc near ; CODE XREF: sub_10014B70+6Ap
.text:10011217              jmp sub_10014C90
.text:10011217 sub_10011217 endp

image

@0x10014CE8 vtable is set in the scriptable object.

.text:10014CE8 mov dword ptr [eax], offset off_1001CAB8

@off_1001CAB8 you can find the vtable.

.rdata:1001CAB8 off_1001CAB8 dd offset sub_10011023 ; DATA XREF: sub_10014C90+58o
.rdata:1001CAB8 ; sub_10014EA0+45o
.rdata:1001CABC dd offset sub_1001108C
.rdata:1001CAC0 dd offset sub_1001105F
.rdata:1001CAC4 dd offset sub_1001107D
.rdata:1001CAC8 dd offset sub_100113ED
.rdata:1001CACC dd offset sub_1001121C
.rdata:1001CAD0 dd offset sub_10011384
.rdata:1001CAD4 dd offset sub_100112D0
.rdata:1001CAD8 dd offset sub_10011140
.rdata:1001CADC dd offset sub_100112DF
.rdata:1001CAE0 dd offset sub_10011113

Now, we have the address, but how do we know which function we want to analyse.If you see the npruntime example, you will get the address of function we are interested.

(The way it is arranged, affects the way vtable is built. Probably here we may need to do more analysis.)

class ScriptablePluginObjectBase : public NPObject
{
    public:
              ScriptablePluginObjectBase(NPP npp) : mNpp(npp)
             {
             }

            virtual ~ScriptablePluginObjectBase() 
            {
            }

           // Virtual NPObject hooks called through this base class. Override as you see fit.
           virtual void Invalidate(); 
           virtual bool HasMethod(NPIdentifier name);
           virtual bool Invoke(NPIdentifier name, const NPVariant *args,
           uint32_t argCount, NPVariant *result);
           virtual bool InvokeDefault(const NPVariant *args, uint32_t argCount,
           NPVariant *result);
           virtual bool HasProperty(NPIdentifier name);
           virtual bool GetProperty(NPIdentifier name, NPVariant *result); 
           virtual bool SetProperty(NPIdentifier name, const NPVariant *value);
           virtual bool RemoveProperty(NPIdentifier name);
           virtual bool Enumerate(NPIdentifier **identifier, uint32_t *count);
           virtual bool Construct(const NPVariant *args, uint32_t argCount, NPVariant *result);

Now, vtable looks like this,

.rdata:1001CAB8 off_1001CAB8 dd offset destrutor ; DATA XREF: sub_10014C90+58o
.rdata:1001CAB8 ; sub_10014EA0+45o
.rdata:1001CABC            dd offset Invalidate
.rdata:1001CAC0            dd offset HasMethod
.rdata:1001CAC4            dd offset Invoke
.rdata:1001CAC8            dd offset InvokeDefault
.rdata:1001CACC            dd offset HasProperty
.rdata:1001CAD0           dd offset GetProperty
.rdata:1001CAD4           dd offset SetProperty
.rdata:1001CAD8           dd offset RemoveProperty
.rdata:1001CADC           dd offset Enumerate
.rdata:1001CAE0            dd offset Construct

Now, if you follow HasMethod pointer then we can find what are the “exported” functions are.

image

You can find that, it has a string comparison for “Add” interface. Similarly we need to trace other property functions and find the properties.Attaching the IDC script for creating structure/union of NPAPI plugin (npruntime.h). I used xulrunner-1.9.2.15.en-US.win32.sdk for creating this IDC script.

#include <idc.idc>

static main(void)
{
    // Enum
    Add_NPPVariable();
    Add_NPVariantType();
   
    // Union
   
    // Struct
    Add_NPPluginFuncs();
    Add_NPNetscapeFuncs();
    Add_NPObject();
    Add_NPClass();
   

}

// Struct functions
static Add_NPClass()
{
    auto id;
    id = AddStrucEx(-1,"NPClass",0);
   
    AddStrucMember(id,"structVersion",                     0X0,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPAllocateFunctionPtr",            0X4,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPDeallocateFunctionPtr",        0X8,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPInvalidateFunctionPtr",        0XC,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPHasMethodFunctionPtr",            0X10,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPInvokeFunctionPtr",            0X14,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPInvokeDefaultFunctionPtr",        0X18,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPHasPropertyFunctionPtr",        0X1C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPGetPropertyFunctionPtr",        0X20,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPSetPropertyFunctionPtr",        0X24,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPRemovePropertyFunctionPtr",    0X28,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPEnumerationFunctionPtr",        0X2C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPConstructFunctionPtr",            0X30,    FF_DWRD,    -1,    4);
}

static Add_NPObject()
{
    auto id;
    id = AddStrucEx(-1,"NPObject",0);
   
    AddStrucMember(id,"NPClass_ptr",                0X0,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"referenceCount",                0X4,    FF_DWRD,    -1,    4);
}

static Add_NPNetscapeFuncs()
{
    auto id;
    id = AddStrucEx(-1,"_NPNetscapeFuncs",0);
   
    AddStrucMember(id,"size",                                0X0,    FF_WORD,    -1,    2);
    AddStrucMember(id,"version",                            0X2,    FF_WORD,    -1,    2);
    AddStrucMember(id,"NPN_GetURLProcPtr",                    0X4,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_PostURLProcPtr",                    0X8,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_RequestReadProcPtr",                0XC,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_NewStreamProcPtr",                0X10,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_WriteProcPtr",                    0X14,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_DestroyStreamProcPtr",            0X18,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_StatusProcPtr",                    0X1C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_UserAgentProcPtr",                0X20,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_MemAllocProcPtr",                0X24,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_MemFreeProcPtr",                    0X28,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_MemFlushProcPtr",                0X2C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_ReloadPluginsProcPtr",            0X30,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_GetJavaEnvProcPtr",                0X34,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_GetJavaPeerProcPtr",                0X38,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_GetURLNotifyProcPtr",            0X3c,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_PostURLNotifyProcPtr",            0X40,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_GetValueProcPtr",                0X44,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_SetValueProcPtr",                0X48,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_InvalidateRectProcPtr",            0X4C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_InvalidateRegionProcPtr",        0X50,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_ForceRedrawProcPtr",                0X54,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_GetStringIdentifierProcPtr",        0X58,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_GetStringIdentifiersProcPtr",    0X5C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_GetIntIdentifierProcPtr",        0X60,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_IdentifierIsStringProcPtr",        0X64,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_UTF8FromIdentifierProcPtr",        0X68,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_IntFromIdentifierProcPtr",        0X6C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_CreateObjectProcPtr",            0X70,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_RetainObjectProcPtr",            0X74,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_ReleaseObjectProcPtr",            0X78,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_InvokeProcPtr",                    0X7C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_InvokeDefaultProcPtr",            0X80,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_EvaluateProcPtr",                0X84,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_GetPropertyProcPtr",                0X88,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_SetPropertyProcPtr",                0X8C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_RemovePropertyProcPtr",            0X90,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_HasPropertyProcPtr",                0X94,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_HasMethodProcPtr",                0X98,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_ReleaseVariantValueProcPtr",        0X9C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_SetExceptionProcPtr",            0XA0,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_PushPopupsEnabledStateProcPtr",    0XA4,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_PopPopupsEnabledStateProcPtr",    0XA8,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_EnumerateProcPtr",                0XAC,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_PluginThreadAsyncCallProcPtr",    0XB0,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_ConstructProcPtr",                0XB4,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_GetValueForURLPtr",                0XB8,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_SetValueForURLPtr",                0XBC,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPN_GetAuthenticationInfoPtr",        0XC0,    FF_DWRD,    -1,    4);
}

static Add_NPPluginFuncs()
{
    auto id;
    id = AddStrucEx(-1,"_NPPluginFuncs",0);
   
    AddStrucMember(id,"size",                        0X0,    FF_WORD,    -1,    2);
    AddStrucMember(id,"version",                    0X2,    FF_WORD,    -1,    2);
    AddStrucMember(id,"NPP_NewProcPtr",                0X4,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_DestroyProcPtr",            0X8,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_SetWindowProcPtr",        0XC,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_NewStreamProcPtr",        0X10,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_DestroyStreamProcPtr",    0X14,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_StreamAsFileProcPtr",    0X18,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_WriteReadyProcPtr",        0X1C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_WriteProcPtr",            0X20,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_PrintProcPtr",            0X24,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_HandleEventProcPtr",        0X28,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_URLNotifyProcPtr",        0X2C,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"javaClass",                    0X30,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_GetValueProcPtr",        0X34,    FF_DWRD,    -1,    4);
    AddStrucMember(id,"NPP_SetValueProcPtr",        0X38,    FF_DWRD,    -1,    4);
}

// Enum functions
static addit(id,ename,evalue)
{
    auto vid;
    vid = AddConstEx(id,ename,evalue,-1);
    if (vid == CONST_ERROR_NAME)
    {
        Message("Duplicate name %s %0Xh\n",ename,evalue);
    }
    else if (vid == CONST_ERROR_VALUE)
    {
        Message("Duplicate value %s == %s  %0Xh\n", ename,evalue);
    }
}

static Add_NPVariantType()
{
    auto id;
    id=AddEnum(GetEnumQty() + 1, "NPVariantType", FF_0NUMH);
   
    addit(id,"NPVariantType_Void"        ,0);
    addit(id,"NPVariantType_Null"        ,1);
    addit(id,"NPVariantType_Bool"        ,2);
    addit(id,"NPVariantType_Int32"        ,3);
    addit(id,"NPVariantType_Double"        ,4);
    addit(id,"NPVariantType_String"        ,5);
    addit(id,"NPVariantType_Object"        ,6);
}

static Add_NPPVariable()
{
    auto id;
    id=AddEnum(GetEnumQty() + 1, "NPPVariable", FF_0NUMH);
   
    addit(id,"NPPVpluginNameString"                    ,1);
    addit(id,"NPPVpluginDescriptionString"            ,2);
    addit(id,"NPPVpluginWindowBool"                    ,3);
    addit(id,"NPPVpluginTransparentBool"            ,4);
    addit(id,"NPPVjavaClass"                        ,5);
    addit(id,"NPPVpluginWindowSize"                    ,6);
    addit(id,"NPPVpluginTimerInterval"                ,7);
    addit(id,"NPPVpluginScriptableInstance"            ,10);
    addit(id,"NPPVpluginScriptableIID"                ,11);
    addit(id,"NPPVjavascriptPushCallerBool"            ,12);
    addit(id,"NPPVpluginKeepLibraryInMemory"        ,13);
    addit(id,"NPPVpluginNeedsXEmbed"                ,14);
    addit(id,"NPPVpluginScriptableNPObject"            ,15);
    addit(id,"NPPVformValue"                        ,16);
    addit(id,"NPPVpluginUrlRequestsDisplayedBool"    ,17);
    addit(id,"NPPVpluginWantsAllNetworkStreams"        ,18);
    addit(id,"NPPVpluginDrawingModel"                ,1000);
    addit(id,"NPPVpluginWindowlessLocalBool"        ,2002);
   
}

Advertisements
This entry was posted in Chrome, Firefox, NPAPI, Safari and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s