Programming


Two months ago Halvar Flake announced a new malware challenge for female reversers only. I’m a man and I couldn’t submit a solution but I decided to give it a try, challenges are always funny. I shared this reversing session with Kayaker, so credit for this blog post goes to him too.

The solution posted by Marion Marschalek (congratulations!) is pretty nice and it explains almost everything in details. I’m not writing a blog post with the same information she gave, but I would like to add something about the way I used to automatically naming/resolving the imported functions.
The idea is to change instructions like:
.text:0040100B call dword ptr [ecx+220h]
into something like:
.text:0040100B call dword ptr [ecx+_API.malloc]

To perform this switch I have written an IDC script. There are two functions inside it, GetAPINames and ResolveAPINames. The first function is used to retrieve the name of all the hidden API while the other one will change the call instructions into a new readable version.
The script stores all the information inside a structure named _API which is filled with all the API names. The structure is necessary and I’ll use it for some minor manual fix too.

GetAPINames
There’s no trace of clear API names inside the disasm, everything is constructed at runtime inside call 402DB0, take a look at this piece of code (without unnecessary junk code lines):

00403E42 C6 44 24 24 43 mov [esp+179CCh+var_179A8], 'C'
...
00403E49 C6 44 24 25 72 mov [esp+179CCh+var_179A7], 'r'
...
00403EC1 C6 44 24 26 65 mov [esp+179CCh+var_179A6], 'e'
...
00403F14 C6 44 24 2F 61 mov [esp+179D4h+var_179A5], 'a'
00403F19 C6 44 24 30 74 mov [esp+179D4h+var_179A4], 't'
00403F1E C6 44 24 31 65 mov [esp+179D4h+var_179A3], 'e'
00403F23 C6 44 24 32 54 mov [esp+179D4h+var_179A2], 'T'
00403F28 C6 44 24 33 68 mov [esp+179D4h+var_179A1], 'h'
00403F2D C6 44 24 34 72 mov [esp+179D4h+var_179A0], 'r'
00403F32 C6 44 24 35 65 mov [esp+179D4h+var_1799F], 'e'
00403F37 C6 44 24 36 61 mov [esp+179D4h+var_1799E], 'a'
00403F3C C6 44 24 37 64 mov [esp+179D4h+var_1799D], 'd'
00403F41 C6 44 24 38 00 mov [esp+179D4h+var_1799C], 0

As you can see CreateThread string is obtained appending every single char. To create names the malware uses another similar way:

00406EC9 C6 84 24 BC 0F 00 00 47 mov [esp+179CCh+var_16A10], 'G'
00406ED1 C6 84 24 BD 0F 00 00 65 mov [esp+179CCh+var_16A0F], 'e'
...
00406F4C C6 84 24 BE 0F 00 00 74 mov [esp+179CCh+var_16A0E], 't'
...
00406FA5 C6 84 24 C7 0F 00 00 4D mov [esp+179D4h+var_16A0D], 'M'
00406FAD C6 84 24 C8 0F 00 00 6F mov [esp+179D4h+var_16A0C], 'o'
00406FB5 C6 84 24 C9 0F 00 00 64 mov [esp+179D4h+var_16A0B], 'd'
00406FBD C6 84 24 CA 0F 00 00 75 mov [esp+179D4h+var_16A0A], 'u'
00406FC5 C6 84 24 CB 0F 00 00 6C mov [esp+179D4h+var_16A09], 'l'
00406FCD C6 84 24 CC 0F 00 00 65 mov [esp+179D4h+var_16A08], 'e'
00406FD5 C6 84 24 CD 0F 00 00 46 mov [esp+179D4h+var_16A07], 'F'
00406FDD C6 84 24 CE 0F 00 00 69 mov [esp+179D4h+var_16A06], 'i'
00406FE5 C6 84 24 CF 0F 00 00 6C mov [esp+179D4h+var_16A05], 'l'
00406FED C6 84 24 D0 0F 00 00 65 mov [esp+179D4h+var_16A04], 'e'
00406FF5 C6 84 24 D1 0F 00 00 4E mov [esp+179D4h+var_16A03], 'N'
00406FFD C6 84 24 D2 0F 00 00 61 mov [esp+179D4h+var_16A02], 'a'
00407005 C6 84 24 D3 0F 00 00 6D mov [esp+179D4h+var_16A01], 'm'
0040700D C6 84 24 D4 0F 00 00 65 mov [esp+179D4h+var_16A00], 'e'
00407015 C6 84 24 D5 0F 00 00 45 mov [esp+179D4h+var_169FF], 'E'
0040701D C6 84 24 D6 0F 00 00 78 mov [esp+179D4h+var_169FE], 'x'
00407025 C6 84 24 D7 0F 00 00 41 mov [esp+179D4h+var_169FD], 'A'
0040702D C6 84 24 D8 0F 00 00 00 mov [esp+179D4h+var_169FC], 0

The way used to create GetModuleFileNameExA is pretty similar to the previous one but there’s a little difference, look at the opcodes. The mov instructions are similar but the ModR/M byte defines a distinct displacement.
Is it possible to recognize and isolate all the instructions used to create all those strings? Well, it’s not so hard because some bytes are fixed! The idea is to parse all the instructions inside 402DB0 trying to recognize those two special mov instructions:

if (Byte(currAddress) == 0xC6) {
  if (Byte(currAddress+1) == 0x44) {
    if (Byte(currAddress+2) == 0x24) {
      if (Byte(currAddress+4) != 0x00) {
        // Get current char and append it to partial name
        szChar = sprintf("%c", Byte(currAddress+4));
        szAPI = sprintf("%s", szAPI + szChar);
      } else {
        if ((strstr(szAPI, ".DLL") == -1) && (strstr(szAPI, ".dll") == -1))
        {
          // Add member to struct (no DLL name)
          AddStrucMember(id, szAPI, -1, FF_DATA, -1, 4);
        }
        szAPI = sprintf("%s", ""); // reset for next string
      }
    }
  }
}

The instructions are checked byte by byte and the strings are created char by char. szChar is the current char to append to the partial string szAPI.
There’s a little problem with this parser, it constructs DLL names too. I’m not interested in DLL names, so a check over the formatted string is necessary:

if ((strstr(szAPI, ".DLL") == -1) && (strstr(szAPI, ".dll") == -1))

Now that I’m sure I don’t have a DLL name I can insert it into the structure:

AddStrucMember(id, szAPI, -1, FF_DATA, -1, 4);

The use of the structure is fondamental for the script.
Now that you know how to parse the first type of mov instruction you can easily change some checks over the fixed bytes and you’ll retrieve names like GetModuleFileNameExA too:

if (Byte(currAddress) == 0xC6) {
  if (Byte(currAddress+1) == 0x84) {
    if (Byte(currAddress+2) == 0x24) {
      if (Byte(currAddress+5) == 0x00) {
        if (Byte(currAddress+6) == 0x00)     {
          if (Byte(currAddress+7) != 0x00) {
            ...

This part of the script works pretty fine but it has a little problem with few functions. To understand it here is an example with GetQueuedCompletionStatus:

00405C2A mov [esp+179CCh+var_179A8], 'G'
00405C31 mov [esp+179CCh+var_179A7], 'e'
00405CA9 mov [esp+179CCh+var_179A6], 't'
00405CF3 mov bl, 'Q'
00405CFE mov [esp+179D4h+var_179A5], bl
00405D02 mov [esp+179D4h+var_179A4], 'u'
00405D07 mov [esp+179D4h+var_179A3], 'e'
00405D0C mov [esp+179D4h+var_179A2], 'u'
00405D11 mov [esp+179D4h+var_179A1], 'e'
00405D16 mov [esp+179D4h+var_179A0], 'd'
00405D1B mov [esp+179D4h+var_1799F], 'C'
00405D20 mov [esp+179D4h+var_1799E], 'o'
00405D25 mov [esp+179D4h+var_1799D], 'm'
...

As you can see the letter ‘Q’ is obtained by a sequence of two instructions and my script is not able to catch it; it creates GetueuedCompletionStatus name. It has been proved that human brain is able to recognize word without few letters or with scrambled letters so I think I can pass over this minor problem!

ResolveAPINames
Ok, now that I have the API structure I need to use it for the resolution part. The function ResolveAPINames scans the entire disasmed code trying to fix the necessary calls. To identify the call you can use a simple strstr function, and to convert it you can use OpStroff (it converts operand to an offset in a structure):

if(strstr(GetDisasm(ea), "call dword ptr") != -1) {
  OpStroff(ea, 0, GetStrucIdByName("_API"));

The malware uses a nice addressing method and IDA is not able to parse the hidden API but the nature of the addressing method lets us to solve the problem with some lines of code only. Now you can understand why the structure is the core of the entire script.

Manual fix
The script is able to resolve 678 calls, but it fails to fix some special cases like this:

00414E36 lea esi, [eax+1FCh]
00414E3C call dword ptr [eax+_API.GetTickCount]
00414E42 push eax
00414E43 call dword ptr [esi]

GetTickCount has been resolved but the next call not. It’s obvious that esi points to the API at offset 0x1FC. You can solve it manually because the structure contains it. Right click over 0x1FC and select the line “[eax+_API.srand]“. Now you know how to manually fix special cases too.

Can I blog an incomplete solution or an incomplete analysis? Why not! That’s the spirit of this blog entry!

More than one year ago I started a project with Kayaker, we decided to write a tool able to show hidden callbacks. If I remember correctly the idea was born while we were putting our hands on a rootkit. In the same days I bet there were many reversers around thinking the same thing because the same tool was developed by others. As you can imagine our tool never see the light, but not because there are similar tools available online; mostly because we are two old lazy reversers!

I bet you are thinking: why the hell are you writing this stupid intro? Well, the tools I mentioned before were bugged and some months ago I discovered the same thing, they are still bugged (I don’t know if they have solved their problems right now…). Strange that no one else noticed it yet.
Anyway, we won’t complete the tool, but with this blog post I would like to tell you some notes about our investigations. At the beginning I wanted to write a detailed and complete article about the subject, but I don’t know when I’ll be able to end this project so I decided to spread out some of my notes.

It’s a sort of two minds work so credit goes to Kayaker too!

The idea is to try to retrieve hidden callbacks that has been installed via CmRegisterCallback, PsSetCreateProcessNotifyRoutine, PsSetCreateThreadNotifyRoutine and PsSetLoadImageNotifyRoutine. After that it would be good to deregister one or more of them.



Where to start?
First of all you have to understand what’s behind functions like CmRegisterCallback, and others. Then, you’ll have something to work on. I’ll start with CmRegisterCallback (from XP SP2), the function is used to register a RegistryCallback routine, and I think the XP version is the most simple one to fully undestand the principles behind the function. There are some differencies between XP and 7 versions, but I think you’ll be able to fully understand 7 structure too! Here is the disassembled function (without useless parts of course):

487E6B  push   'bcMC'                          ; Pool Tag: "CMcb"
487E70  xor    ebx, ebx
487E72  push   38h                             ; NumberOfBytes: 0x38
487E74  inc    ebx
487E75  push   ebx                             ; PoolType: PAGEDPOOL
487E76  call   ExAllocatePoolWithTag           ; ExAllocatePoolWithTag(x,x,x): allocates pool memory
487E7B  mov    esi, eax                        ; eax is the pointer to the allocated pool memory, PCM_CALLBACK_CONTEXT_BLOCK
487E7D  xor    edi, edi
487E7F  cmp    esi, edi                        ; Is PCM_CALLBACK_CONTEXT_BLOCK a NULL pointer?
487E81  jz     cmRegisterCallback_fails        ; yes: function fails...
487E87  push   esi
487E88  push   [ebp+Function]                  ; PEX_CALLBACK_FUNCTION, pointer to callback function
487E8B  call   _ExAllocateCallBack             ; allocates and fill EX_CALLBACK_ROUTINE_BLOCK structure (more on this later...)
487E90  cmp    eax, edi                        ; ExAllocateCallback success or not?
487E92  mov    [ebp+PEX_CALLBACK_ROUTINE_BLOCK], eax ; store the pointer to the allocated pool memory
487E95  jnz    short _ExAllocateCallBack_success
   ...                                         ; fill CM_CALLBACK_CONTEXT_BLOCK fields
487EDC  mov    ebx, offset CmpCallBackVector
487EE1  mov    [ebp+i], edi                    ; i = 0
487EE4 try_next_slot:
487EE4  push   edi                             ; OldBlock: NULL
487EE5  push   [ebp+PEX_CALLBACK_ROUTINE_BLOCK] ; NewBlock with information to add
487EE8  push   ebx                             ; CmpCallbackVector[i]
487EE9  call   _ExCompareExchangeCallBack   ; try to *insert* the new callback inside CmpCallBack vector
487EEE  test   al, al                       ;check the result...
487EF0  jnz    short free_slot_has_been_found    ; jump if the vector has an empty space for the new entry
487EF2  add    [ebp+i], 4                      ; i++, increase the counter
487EF6  add    ebx, 4                          ; shift to the next item of the vector to check
487EF9  cmp    [ebp+i], 190h                   ; is the end of the vector? 
487F00  jb     short try_next_slot             ; no: try another one. yes: no free slot!
   ...    
487F11 cmRegisterCallback_fails:
487F11  mov    eax, STATUS_INSUFFICIENT_RESOURCES
487F16 end_CmRegisterCallback:
   ...
487F1A  retn   0Ch
   ... 
487F1D free_slot_has_been_found:
487F1D  mov    eax, 1
487F22  mov    ecx, offset _CmpCallBackCount   ; CmpCallBackCount: number of not NULL item inside the vector
487F27  xadd   [ecx], eax                      ; there's a new callback, it increases the number of item inside the vector
487F2A  xor    eax, eax
487F2C  jmp    short end_CmRegisterCallback




As you can see the idea behind the function is really simple!
Basically, it tries to add a new entry inside a vector named CmpCallBackVector, and when the entry is correctly inserted the registration process will end with a success.
How do I know is it using a vector? The add instruction at 0x487EF6 represents a clear clue, and the cmp at 0x487EF9 reveals the fixed length of the vector (the vector has 100 items (0×190/4…)). Now that I have this information I’m going to try to explain the entire procedure in detail. The algorithm could be divided into 5 big blocks:

1: try to allocate 0×38 bytes for a structure named CM_CALLBACK_CONTEXT_BLOCK
2: try to allocate 0x0C bytes for a structure named EX_CALLBACK_ROUTINE_BLOCK
3: fill CM_CALLBACK_CONTEXT_BLOCK fields
4: look for an empty slot, insert a sort of PEX_CALLBACK_ROUTINE_BLOCK in it and update CmpCallBackCount
5: notify success or error and exit

Point #1 is pretty simple to understand, it’s only a call to ExAllocatePoolWithTag.

To understand point #2 you have to see what’s going on behind ExAllocateCallBack procedure. Let’s start taking a look at it:

52AB35  push   'brbC'                              ; Pool Tag: Cbrb
52AB3A  push   0Ch                                 ; NumberOfBytes: 0x0C
52AB3C  push   1                                   ; PoolType: PAGED_POOL
52AB3E  call   ExAllocatePoolWithTag               ; alloc a EX_CALLBACK_ROUTINE_BLOCK structure
52AB43  test   eax, eax                            ; ExAllocatePoolWithTag success or not?
52AB45  jz     short _ExAllocateCallBack_fails
52AB47  mov    ecx, [ebp+_pex_callback_function]   ; pointer to callback function (PEX_CALLBACK_FUNCTION)
52AB4A  and    dword ptr [eax], 0                  ; 1° field: 0
52AB4D  mov    [eax+4], ecx                        ; 2° field: _pex_callback_function
52AB50  mov    ecx, [ebp+_pool_allocated_memory]   ; PCM_CALLBACK_CONTEXT_BLOCK
52AB53  mov    [eax+8], ecx                        ; 3° field: _pcm_callback_context_block
52AB56 _ExAllocateCallBack_fails:
   ...




The procedure is used to allocate and fill a special structure:

typedef struct _EX_CALLBACK_ROUTINE_BLOCK
{
EX_RUNDOWN_REF RundownProtect;
PEX_CALLBACK_FUNCTION Function;
PCM_CALLBACK_CONTEXT_BLOCK Context;
} EX_CALLBACK_ROUTINE_BLOCK, *PEX_CALLBACK_ROUTINE_BLOCK;

As you can see from the lines above the first field has been setted to 0 while the other fields are filled with two pointers: the function to register and the context containing info about the callback.

While point #3 is just a series of mov instructions used to fill CM_CALLBACK_ROUTINE_BLOCK structure, point #4 gives some usefull information to us: CmpCallBackVector has 100 elements and this part of code is used to scan the entire vector until an empty element is found. A failure leads us to a non-registration of the callback. What happens when there’s a empty slot inside the vector? The new entry will be added inside the vector. Most of the job is done by the function named ExCompareExchangeCallBack, here is the core of the function:

52AB81  mov    eax, [ebp+CmpCallbackVector]    ; vector at the current position
52AB84  mov    ebx, [eax]                      ; ebx is a PEX_CALLBACK_ROUTINE_BLOCK, the item could be NULL or not
52AB86  mov    eax, ebx
52AB88  xor    eax, [ebp+OldBlock]             ; OldBlock is NULL for a registration process
52AB8B  mov    [ebp+current_pex_callback_routine_block], ebx
52AB8E  cmp    eax, 7                          ; check used to see if the current item is NULL or not
52AB91  ja     short loc_52ABB5                ; jump if not NULL
52AB93  test   esi, esi                        ; is NewBlock NULL?
52AB95  jz     short loc_52ABA1                ; jump if it's NULL
52AB97  mov    eax, esi                        ; esi, NewBlock pointer (changed...)
52AB99  or     eax, 7                          ; PAY ATTENTION HERE: or 7 !?!
52AB9C  mov    [ebp+NewBlock], eax             ; change NewBlock pointer: NewBlock = NewBlock OR 7
52AB9F  jmp    short loc_52ABA5
   ...
52ABA5 mov    eax, [ebp+var_4]               ; here if CmpCallbackVector's item is null
52ABA8  mov    ecx, [ebp+CmpCallbackVector]    ; current empty slot
52ABAB  mov    edx, [ebp+NewBlock]             ; new pointer to insert
52ABAE  cmpxchg [ecx], edx                     ; insert the new pointer inside the empty slot!
52ABB1 cmp    eax, ebx
52ABB3 jnz    short loc_52AB81
52ABB5 and    ebx, not 7                     ; PAY ATTENTION HERE!
52ABB8 cmp    ebx, [ebp+OldBlock]            ; here if CmpCallbackVector's item is not null
52ABBB jnz    short loc_52AC19
52ABBD test   ebx, ebx
52ABBF jz     short loc_52AC15




The routine contains some more things inside, but we can stop here with the analysis because we have everything we need. If the pointer to the NewBlock to insert is not NULL and there’s an available empty slot the pointer is inserted inside the vector; after that CmpCallBackCount value will be updated (remember the snippet at the beginning of this blog entry?).

The last part of the algorithm (point #5) is a simple return with a success or insuccess value:

52AC15 mov    al, 1                          ; 1 means success, new item has been added to CmpCallbackVector
52AC17 jmp    short loc_52AC29
52AC19 test   esi, esi                      ; esi -> NewBlock 
52AC1B jz     short loc_52AC27
52AC1D push   8                       
52AC1F pop    edx
52AC20 mov    ecx, esi
52AC22 call   ExReleaseRundownProtectionEx   ; if esi is not null something went wrong...
52AC27 xor    al, al                         ; 0 means insuccess, new item has not been added to CmpCallbackVector




Ok, I think we have a general idea about the vector; each entry contains a *sort* of pointer to a EX_CALLBACK_ROUTINE_BLOCK, and to reveal all of them you only have to scan the entire vector!

To sum up, I have 3 possible scenes:
1. CmpCallbackVector’s item is empty:
the new block will be inserted inside the vector. The added value is not the one passed to ExCompareExchangeCallBack, but it’s the value modified by a “OR 7″ logic operation.
2. CmpCallbackVector’s item is full:
it simply returns STATUS_INSUCCESS and it will try with the next item of the vector
3. Someone is working on the CmpCallbackVector’s item:
the registration process reveals an interesting behaviour, just to be sure to be the only one accessing the resource the system uses a lock mechanism. The OR and AND operations are the core of that mechanism (0x52AB99 and 0x52ABB5, commented using “PAY ATTENTION HERE!”). If the current item of the vector is not NULL the compare instruction at 0x52AB8E fails and the code flow continues from 0x52ABB5. At this point the real address of the item is extracted (stored_value AND NOT 7) and compared with NULL; it’s obviously not NULL and as you can see around 0x52AC22 the resource is released because someone else is working on it. Now you should understand why the hell the system uses to OR by 7 the value to add inside the vector.

With all this kind of information I can finally write a routine able to read all the stored callbacks:

cells = 0x64;                    // cells inside CmpCallbackVector
nMod = *(DWORD*)_sysmodBuffer;   //	_sysmodBuffer filled by "ZwQuerySystemInformation(SystemModuleInformation..."
for(i=0;i<cells;i++)
{
   // take current item from CmpCallbackVector (look at the "& ~7" operation)
   pCBRB = (PEX_CALLBACK_ROUTINE_BLOCK)((*(DWORD*)(_CmpCallbackVectorAddress + 4*i )) & ~7);
   if (pCBRB != 0)
   {
      sysmodTmp = (PSYSTEM_MODULE_INFORMATION)((DWORD)_sysmodBuffer + 4);
      j = 0;
      while (jFunction) Base + (DWORD)sysmodTmp->Size) &&
			((DWORD)pCBRB->Function) > ((DWORD)sysmodTmp->Base))
         {
            // Callback has been found
            DbgPrint("Result: %LX: %s\r\n", pCBRB->Function, sysmodTmp->ImageName);
            break;
	 }
	 // get the next module
	 sysmodTmp = (PSYSTEM_MODULE_INFORMATION)((DWORD)sysmodTmp + sizeof(SYSTEM_MODULE_INFORMATION));
	 j = j + 1;
    }
}




It’s important to scan all the cells inside the vector! One of the tool available on the web fails to retrieve callbacks stored after an empty element of the vector.

Well, the only thing to reveal about the code above is CmpCallbackVectorAddress, the address of CmpCallBackVector. How can I locate the exact address of CmpCallBackVector? Imho, that’s the hardest part of the entire process!



How to find CmpCallbackVector address
To develop a tool for a specific OS is pretty easy because the vector’s address is hardcoded; it would be nice to discover an OS independent technique.
I think the most used approach is a byte-search based on a specific sequence of bytes; it’s a nice idea but I don’t want to list every OS version known to man inside my source code. We (I and kayaker) spent a lot of time over this point, we both wanted to develop something that is not totally related to a specific OS version; something that doesn’t require a series of “if OS == xxx” statements inside the code. It’s quite impossible to write a non OS dependent code but I believe it’s possible to remove some OS checks from the code.

We finally came up with two ideas, a practical and a theoretical idea. I hate theory and mine is the practical solution of course. I think both ideas are valid and just to be sure to find the right vector’s address we decided to combine them inside a hypothetical tool, four eyes are always better than two!



The practical approach
My idea is really simple, since of the vector’s address is hardcoded you’ll surely have it in two different parts of the code:

PAGE:005392D0   BB 20 05 48 00   mov    ebx, offset _CmpCallBackVector
.data:00480520                   _CmpCallBackVector db    0




The address is inside two sections, PAGE and data. An *xref-search* is the core of the idea! It’s pretty stupid indeed, but from what I’ve seen so far it works!
The pseudo code of my xref search is explained here, basically it scans the entire PAGE section trying to locate the right address:

callbackAddress = CmUnregisterCallback address in memory
pagePointer = pointer_to_PAGE_section
while (pagePointer < pointer_to_PAGE_section + size_of_PAGE_section)   
{
   value = get dword pointed by pagePointer
   if (value is inside DATA section)
      if ((pagePointer > callbackAddress) && (pagePointer < callbackAddress + range))   
      {
         CmpCallbackVector = value
	 exit!
      }
   pagePointer++      
}




As you can imagine a simple xref-search is unable to find out the right value, you need one more check. That’s why I added the line:

if ((pagePointer > callbackAddress) && (pagePointer < callbackAddress + range))   




where callbackAddress is the address of CmUnregisterCallback. What does it mean? Well, ‘pagePointer’ should be inside the first “range” bytes of CmUnregisterCallback function. If both “if” statements are satisfied I’m pretty sure about the vector’s address value.

There are still 2 points to clarify:
- what's range variable?
- why CmUnregisterCallback?

range is just a numerical value and you'll only have to decide a value to assign to it. Under XP the first bytes of the CmUnregisterCallback function are:

PAGE:005392C3 8B FF           mov    edi, edi
PAGE:005392C5 55              push   ebp
PAGE:005392C6 8B EC           mov    ebp, esp
PAGE:005392C8 51              push   ecx
PAGE:005392C9 83 65 FC 00     and    [ebp+var_4], 0
PAGE:005392CD 53              push   ebx
PAGE:005392CE 56              push   esi
PAGE:005392CF 57              push   edi
PAGE:005392D0 BB 20 05 48 00  mov    ebx, offset _CmpCallBackVector




In this specific case 16 could be a possible value… What about the other OSs? Well, as I said before I think it's hard to write a universal piece of code, but as far as I have seen it's possible to adjust the "range" to cover some more OSs. I don't have Vista and 7 running on my system and I'm working on the dead list only, but I think 148 could be a nice value to set and it should cover all the OSs. If you are still reading and you have Vista or 7, can you confirm that?
One more thing about the search pattern: I use CmUnregisterCallback because (inspecting all the OSs) CmRegisterCallback doesn't always store the CmpCallbackVector value inside the main routine, but it hides it under some calls. i.e. look at CmRegisterCallback from 7:

PAGE:0065712A mov  edi, edi
PAGE:0065712C push ebp
PAGE:0065712D mov  ebp, esp
PAGE:0065712F push [ebp+Cookie]
PAGE:00657132 mov  eax, offset stru_4FFDF0
PAGE:00657137 push 1
PAGE:00657139 push [ebp+Context]
PAGE:0065713C push [ebp+Function]
PAGE:0065713F call sub_657153                 ; It's everything inside this call!!!
PAGE:00657144 pop  ebp
PAGE:00657145 retn 0Ch




It’s much more complex to attack a procedure with sub-routines, don't you think? That's why I did opt for CmUnregisterCallback.



What about the PsSet* functions?
At the beginning of this blog post I mentioned some more functions, it's time to spend some words for them too.

The functions are:
PsSetCreateProcessNotifyRoutine
PsSetCreateThreadNotifyRoutine
PsSetLoadImageNotifyRoutine

There are some similarities between CmRegisterCallback and the new three functions: they all register something, they all use a vector to store the information, and they all use the same function! YES, to register a function they use the same scheme:

1. get the address of a specific vector
2. try to insert the new item inside the vector calling ExCompareExchangeCallBack

Just to clarify everything look at this snippet, taken from PsSetCreateThreadNotifyRoutine:

4ED7C4  mov    esi, offset _threadVector   ; the vector
4ED7C9  push   0
4ED7CB  push   ebx
4ED7CC  push   esi
4ED7CD  call   _ExCompareExchangeCallBack   ; the function
4ED7D2  test   al, al
4ED7D4  jnz    short loc_4ED7F3
4ED7D6  add    edi, 4
4ED7D9  add    esi, 4
4ED7DC  cmp    edi, 20h   ; the check over the number of items inside the vector
4ED7DF  jb     short loc_4ED7C9




The only different thing is the length of the vector:
_callbackVector: 0×64 slots
_processVector: 0×8 slots
_threadVector: 0×8 slots
_imageVector: 0×8 slots

Well, you can use all the info I gave you about CmRegisterCallback for these three functions too! I think you'll be able to retrieve all the hidden callbacks, and -just in case- unregister a callback. There are so many ways from the dirty one (put NULL inside the vector's slot) to the right one (calling the right unregister function)… you only have to decide!

While I was trying the code by Joachim Bauch I noticed a strange behaviour loading user32.dll. The test program I’m using to do some tests crashes with an eccess violation error on a portion of memory virtually loaded at runtime.

For those who has not read the article I present a quick sum up of the technique, focusing on the necessary steps only:
1. allocate the necessary bytes required to store all the bytes of the dll
2. copy the original dll bytes inside the new allocated memory buffer
3. perform base relocation adjusting the necessary references
4. call DllEntryPoint directly from the new allocated buffer
5. when you don’t need the dll anymore it frees the allocated buffer

The error occours when the buffer is completely deallocated. The technique seems to be right but the question arises: why the hell someone needs to access an address inside a deallocated memory?

The problem is not strictly related with Joachim’s code itself, it’s an error caused by the use of user32.dll! At the moment I haven’t tried all the system dll, but if you understand the problem I’m pretty sure you’ll be able to solve it with another dll involved.

I have all the source code in front of me but when the problem is not totally related with it I prefer to use a debugger approach.

When the exception occours your debugger breaks here:

7C91E464 MOV EAX,DWORD PTR FS:[18] ; TEB
7C91E46A MOV EAX,DWORD PTR DS:[EAX+30] ; PEB
7C91E46D MOV EAX,DWORD PTR DS:[EAX+2C] ; PEB.KernelCallbackTable
7C91E470 CALL DWORD PTR DS:[EAX+EDX*4] ; call dword ptr [0xB72A10], access violation occours here!

The address (0xB72A10) is inside the allocated buffer, it’s obviously an entry of a vector. EAX represents the starting address of the vector and EDX is an index, each dword is an element of the vector. Starting address is 0xB72970, I only have to understand what’s behind that address.

Load user32.dll inside IDA and look at the vector, the xref will bring you inside DllEntryPoint:

7E39B3F6 mov eax, large fs:18h ; TEB
7E39B3FC mov eax, [eax+30h] ; PEB
7E39B3FF mov eax, [eax+18h] ; PEB.ProcessHeap
7E39B402 mov hHeap, eax
7E39B407 mov eax, large fs:18h
7E39B40D mov eax, [eax+30h]
7E39B410 mov dword ptr [eax+2Ch], offset off_7E392970 ; PEB.KernelCallbackTable

Can you see where the problem is? No!?! Ok, take a look at the same code that has been copied inside the allocated buffer (base relocation performed!):

00B7B3F6 MOV EAX,DWORD PTR FS:[18]
00B7B3FC MOV EAX,DWORD PTR DS:[EAX+30]
00B7B3FF MOV EAX,DWORD PTR DS:[EAX+18]
00B7B402 MOV DWORD PTR DS:[BD1224],EAX
00B7B407 MOV EAX,DWORD PTR FS:[18]
00B7B40D MOV EAX,DWORD PTR DS:[EAX+30]
00B7B410 MOV DWORD PTR DS:[EAX+2C],0B72970 <-- look here!!!

At the beginning of user32.dll there’s a particular initialization, it involves the heap and the KernelCallbackTable address. Both values are changed according to the new image base address but they will not be changed back to the old values.
If you don’t want an access violation inside your program you’ll have to restore the old values, nothing else…

The conclusion is simple, the code is perfectly right but it may be prone to this kind of weird conceptual bug… pay attention when you load a system dll!

In these days I wanted to fix my Reveal Imports plugin. I wrote it some months ago while I was checking a malware (click here for the full story); it’s bugged and it works on some malwares only.
The bad news is that I lost the source code… yes, it sometimes happens. It’s not the end of the world because if you were able to code a bugged program you should be able to write a new bugged one!

The idea of the new plugin is the same: it reveals imports of a dumped process loaded inside Ida.

plugin_reveal_imports

In general, for a non rebuilded dump you’ll have some problems guessing what kind of code will you face after “jmp 7C810DA6″ instruction. The plugin will come in handy when you need to analyze a dump without rebuilding the file using an external tool (i.e. Import Reconstructor).

To use the plugin is pretty easy, start saving it inside IDA plugin directory. Load the file in Ida, move the cursor inside the section containing the code you want to check and hit ALT+z to reveal hidden imports. If there’s something to reveal a window will appear showing the result.

It’s the first release and it’s far from being perfect. Anyway, if you like the plugin idea you can help me telling every kind of bug/problem/strange behaviour it has. This time I’ll try to fix/improve it.

Download

How many times did you create a structure starting from Windbg‘s dt command output? It sometimes happens especially if you use Ida or if you need to code something. It’s something that makes me feel unhappy. It’s a boring job for sure, particularly when you have to deal with big structures (i.e. ethread). There are some ready made definitions online, but there’s not a standard definition for a single structure. Most of the time it depends on the OS you are running on.

All I want to do is to convert dt’s output into a struct definition. The output to convert is something like (obtained by Windbg using “dt _list_entry” command):

ntdll!_LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY

And this is what I want to generate:

typedef struct _LIST_ENTRY
{
struct _LIST_ENTRY* Flink; // 0x000
struct _LIST_ENTRY* Blink; // 0x004
} LIST_ENTRY, *PLIST_ENTRY;

I’m not a Windbg guru and I don’t know if there is a quickest way, so the idea is to write something able to perform (almost all) the convertion.

The gui is pretty simple:

Gui

Two edit boxes and two buttons, nothing more. The convertion process starts by pressing the “Convert” button, the program converts the data stored inside the clipboard. The left box will be filled with the clipboard’s contents while the other box will contain the converted structure. What to store inside the clipboard? Look at the picture below:

Clipboard

Selected text is what you have to store into clipboard, everything starts from ‘_’ character. Once you have saved the text you can convert the structure. Here’s the result:

Convertion

The edit box is editable, it’s necessary because most of the time it’s hard to predict the right type to display. I don’t know if it’s possible to perform a perfect convertion, the aim of this tool is to speed up the convertion process. With some minor changes you should be able to obtain a perfect convertion.

This tool is not totally complete, I have some more things to add. As usual I didn’t test it too much because I prefer to fix it when a bug occours. Anyway, it seems to work fine and you can contact me for comment/criticism/suggestion/etcetc.

You can download the converter here: https://www.box.com/shared/jai5ju0848

ps. HAPPY NEW YEAR!!!

Few days ago I started renewing my PE editor’s gui, I wanted to replace some edit box controls with a listview control. Everything was going well until I had to edit the value inside a cell. With the original listview control you can change the text of the first subitem of a row only, but I would like to edit every single subitem. How can I solve the problem? I didn’t want to waste time solving the problem so I decided to take a look at the usual programming places starting from Code Project. Hm, nothing. I’m not so good in searching information through the net, but seems like there are working samples on mfc, .net and vb only. No win32 programming stuff… Well, I decided to give it a try subclassing the control.
I have never subclass-ed a control before, it’s my first try. I don’t know if there’s a better approach. I don’t even know if it’s the correct way to solve the problem, but it seems to works well. Let’s start.

The steps to follow are:
1. Create an edit box that will be used to insert the new text
2. Set the new window procedure able to handle edit control’s messages
3. Apply/abort text modification

I use VS creating a win32 project. Add a listview control to your dialog setting “Edit labels” to FALSE. If you set the option to TRUE the OS will handle subitem modification, I prefer to avoid this behaviour.

The idea is to change the subitem’s text when a double click occours. I catch the event in the main window procedure calling the function (named SubClass_ListView_Editable) which subclasses the control.

The first step consists of creating the edit box over the clicked subitem. To create the edit box I need to know where to put it. LVM_GETSUBITEMRECT returns information about the rectangle for a subitem of a listview control. With this information I can create the new control:

ListView_GetSubItemRect(hListView, _lParam->iItem, _lParam->iSubItem, LVIR_LABEL, &r);
// Time to create the new edit box
hEditable = CreateWindowEx(0, "EDIT", "Edit me", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_MULTILINE, r.left, r.top, r.right-r.left, r.bottom-r.top, _lParam->hdr.hwndFrom, NULL, hInst, 0);

“r” is defined as a RECT structure:

typedef struct _RECT {
LONG left; // x-coordinate of the upper-left corner of the rectangle
LONG top; // y-coordinate of the upper-left corner of the rectangle
LONG right; // x-coordinate of the lower-right corner of the rectangle
LONG bottom; // y-coordinate of the lower-right corner of the rectangle
} RECT, *PRECT;

As you can see I use “r” inside CreateWindowEx function specifying the coordinates of the new control.
The third parameter of CreateWindowEx is the text that will be shown in the control. I use a static text but you can leave it blank or display the subitem’s text, it’s up to you. Now, the new control has been created and I’m going to set some features:

SendMessage(hEditable, EM_LIMITTEXT, 8, 0); // It accepts no more than 8 chars
SendMessage(hEditable, EM_SETSEL, 0, 8); // Text selected
SetFocus(hEditable); // Focus to the new box

If you don’t need a particular behaviour (limit text, accept only numbers…) you can avoid the first two calls but I think the third one is useful, it gives the focus to the new edit box.

The control is complete, I have to add the new window procedure. This can be done using SetWindoLong function:

LONG SetWindowLong(
HWND hWnd, // Handle of the new edit control
int nIndex, // The attribute to change
LONG dwNewLong // The new value
);

The function changes an attribute of a specified window, in this case I’m going to change the address of the dialog procedure. The aim is to add a new window procedure for handling edit box’s messages only. I’ll pass over all the other messages forwarding them towards the old window procedure.

wpOld = (WNDPROC)SetWindowLong(hEditable, GWL_WNDPROC, SubClass_ListView_WndProc);
SetProp(hEditable, "WP_OLD", (HANDLE)wpOld);

SubClass_ListView_WndProc represents the new dialog procedure.
I have to save the address of the original window procedure because I have to restore it when I’ll destroy the edit box. To save the address I use SetProp function, but if you prefer you can use global variables. To end this piece of code I save some more useful information: row and column of the subitem to change:

SetProp(hEditable, "ITEM", (HANDLE)_lParam->iItem);
SetProp(hEditable, "SUBITEM", (HANDLE)_lParam->iSubItem);

Which kind of messages will I have to catch? WM_KEYDOWN and WM_DESTROY only, all the other messages are passed to the original window procedure in this way:

return CallWindowProc((WNDPROC)GetProp(hEditable, "WP_OLD"), hwnd, uMsg, wParam, lParam);

I catch WM_KEYDOWN because I have to handle ENTER ans ESC key. When you hit ENTER the text will be saved in the subitem, and when you click ESC the operation will be aborted:

case WM_KEYDOWN:
if (LOWORD(wParam) == VK_RETURN)
{
...
// Item and suibtem to change
LvItem.iItem = GetProp(hEditable, "ITEM");
LvItem.iSubItem = GetProp(hEditable, "SUBITEM");
// Where to store the new text
LvItem.pszText = text;
// Get new text and set it in the subitem
GetWindowText(hEditable, text, sizeof(text));
SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)GetProp(hEditable, "ITEM"), (LPARAM)&LvItem);
DestroyWindow(hEditable);
}
else if (LOWORD(wParam) == VK_ESCAPE)
DestroyWindow(hEditable);
break;

If you press ESC the edit box will be destroyed without changing the subitem’s text.
When ENTER is pressed I simply get the text storing it in the subitem. After that I can destroy the edit box.
There’s something more to say about VK_RETURN. Look at CreateWindowEx parameters, there’s a ES_MULTILINE value. The value is necessary otherwise the application refuses to catch ENTER.
The last thing I check in the new window procedure is WM_DESTROY message, I simply remove the saved properties and then I restore the original window procedure calling SetWindowLong again.

What about mouse click when I’m changing the subitem’s value? It’s like VK_ESCAPE key, I remove the edit box aborting the operation. See the attached source code for details.

The picture represents the subclassing method in action:

Listview subclass

The code can be optimized for sure, just fix/change/remove/add everything you need. Feel free to post your comment/suggestion/criticism here.
Download the VS project from here

Game over!

Just a quick post today. Here’s the tool I mentioned in a previous blog entry. I slightly modified something, but the concept is still the same. I wanted to add something more, but at the moment it’s only a new line in my to-do list…
I don’t think you need a help for using the tool, it’s pretty stupid.

The code was written in few hours, but now I don’t have the time to test it carefully. For any bug/comment/criticism/whatever feel free to contact me.

compare_vmware_snapshots.jpg

Download file

Nowadays there’s a big use of virtualization; tools like VMware, VirtualPC and others are daily used. There are some differencies between the original and the virtualized environment, but to study a malware under a protected blackbox it’s very comfortable. You can study their behaviour without any problems.

Just today, while I was running a malware, I got this foolish idea: can I identify hidden files using VMware’s snapshots?

Under VMware you can save the current state of a virtual machine taking a snapshot of the running guest system. The snapshot is stored somewhere in the guest’s OS folder, it simply needs some files. I’m interestered in one file only, the one containing the guest’s memory. The memory is saved inside a file with .vmem extension.

The idea is to take two snapshots (a virgin and an infected system), and then compare the two files. The main problem is that a single snapshot needs a large amounts of bytes, around 260 Mb on my system. Comparing the snapshots using an hex editor is madness. I decided to write a simple application able to compare two files string to string. Why only strings?
Well, how can I identify an hidden file simply looking at a “memory dump”? The answer is simple: the only thing able to reveal a trace is a string containing the name of the hidden file, nothing more. So, I extract all the strings from the virgin snapshot and then I compare them with all the strings from the infected snapshot. Yes, it’s a foolish idea but it helps me to pass a boring afternoon.

The program is pretty simple and easy to implement, here’s the program in action:

Compare_snapshots dialog

The upper listbox control shows all the strings inside the virgin snapshot. To fill the second listbox control I simply search for all the strings inside the snapshot displaying the ones which are not inside the upper listbox.

The most important part of the program is the internal “search engine”. To speed up the program you have to search for specific strings. To view the results in a quick way I simply search for strings with extension “.sys”, “.dll” or just “.exe”. That’s because these are the file extensions of the files that are always hidden. You can improve the search engine adding some more rules (i.e. string must have “system32″ or “windows” inside) but the result won’t change: you can always see some interesting strings.

I tried the program running two malwares: Lager and Nailuj.
Lager malware hides a file named taskdir.exe and Nailuj hides videoati0.sys/dll/exe.
In both cases, I can see some strings referring to the hidden files. Here is a screenshot for Lager:

Compare snapshots taskdir

The string is somewhere in the memory, I’m not interested in its position but in the string itself: it exists!

There are some good tools out there able to show hidden files but sometimes they fail. When they fail you can try with this approach.

I’ll test this approach with some more malwares in the next days. If you want I can share the “Compare snapshots” program, just drop me a mail or write a comment right here.

While I was looking at a malware code I stumbled on a series of functions I have never seen before. The functions are: mixerOpen, mixerGetLineInfo, mixerGetLineControls and mixerSetControlDetails. These are only words for me at first, but the word “mixer” suggested that something related with audio line is involved. Msdn and Google are good friends in this case. I always start from msdn and then I browse the net looking for practical examples, just to see possible implementations. As I thought the functions are used for changing some sound parameters. The malware aims to mute the speakers but it will fail.

Some times ago I was reading an online magazine and there was an article explaining how many malwares contain ripped code. It’s an old news and I agree with it, but I have never meet a live example. The malware I’m checking could be my first one. I think the code is taken directly from a nice tutorial titled mixerSetControlDetails
The tutorial provides a working sample on how to control the volume level of your speakers, you can raise or decrease the level simply moving a slider. The sample is not designed to mute the speakers directly, you have to move the slider to zero. At the end of the tutorial there’s a part titled “Mute me, baby!”, in this part the author writes about a way used to mute the speakers directly. He provides a possible implementation but not a working sample. I tried the code but unfortunatly it doesn’t mute the speakers.
Believe it or not the malware is unable to mute the speakers because the author doesn’t provide a working solution. Yes, part of the malware code is taken directly from this tutorial.

I can’t be 100% sure because I can’t compare two source codes but:
- to mute the speakers you only need 4 functions and not 6. The malware calls the same functions listed in the tutorial in the same order, with the same parameters. That’s strange because the sample changes the volume to 18500 but the aim of the malware is to mute the speaker. It’s strange.
- there are some structures involved in the code and the malware fills all the structures with the same values provided by the tutorial. Maybe you have to initialize only some structure’s members but msdn is pretty clear about these mixer functions, most of the time you need to initialize the entire structure.

Maybe I’m right maybe I’m wrong, I don’t know but there’s a strictly correlation among codes. Just in case you want to mute the speakers here is a working piece of code:

HMIXER hMixer;
MIXERLINE ml;
MIXERLINECONTROLS mlc;
MIXERCONTROL mc;
MIXERCONTROLDETAILS_BOOLEAN mcd_b;
MIXERCONTROLDETAILS mcd;

mixerOpen((LPHMIXER)hMixer, MIXER_OBJECTF_MIXER,0,0,0);
ml.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
ml.cbStruct = sizeof(MIXERLINE);
mixerGetLineInfo((HMIXEROBJ)hMixer, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE);

mlc.cbStruct = sizeof(MIXERLINECONTROLS);
mlc.dwLineID = ml.dwLineID;
mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
mlc.cControls = 1;
mlc.cbmxctrl = sizeof(MIXERCONTROL);
mlc.pamxctrl = &mc;
mixerGetLineControls((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE );

mcd_b.fValue = !mcd_b.fValue;

mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mcd.dwControlID = mc.dwControlID;
mcd.cChannels = 1;
mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
mcd.paDetails = &mcd_b;
mixerSetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_SETCONTROLDETAILSF_VALUE);

Attached the source code and the exe file.

optimus_mini_3.jpgYesterday I have had the opportunity to try this device for my very first time. It’s a nice toy, these buttons are really helpful sometimes. The interesting part is that you can write your own plugin making the device really powerful, shortcuts are useful for most of the applications out there. Art Lebedev offers some plugins but if you want a specific plugin you have to code it by yourself.

It’s really easy to develop a plugin, you can download the plugin skeleton directly from developer’s page to start with. There are some versions, I’ll use the C++ version.
Just to take some confidence with this new device I wrote my first plugin. When I have to learn something new I always start from the basics, the first plugin is a slightly change of the plugin skeleton provided by AL.
My first try it’s a VLC plugin. VLC is my preferred video player and the aim of the plugin is to play/pause a movie simply pressing one of the three mini keyboard buttons. As you’ll see it’s very simple and at the sime very easy to develop.

The core of the skeleton plugin is the file OptPlugin.h. The file contains some define, some macro and the main class definition. Yes, the plugin is class based and the main class is called OptimusMiniPlugin. When you write a plugin you basically define a new class derived from OptimusMiniPlugin implementing the defined methods. The predefined methods are:
- Paint: used to paint the screen
- OnKeyDown: called when the button has been pressed
- GetInfo: your personal “about” system
- GetProperty: allows to get properties from plug-in instance
- SetProperty: allows to set plug-in instance properties
- ShowProperties: shows plug-in properties dialog
- OnEvent: used to control one or more possible events

If you want to write a plugin these are the functions you have to deal with. Obviously you can use them all, delete some of them and so on, it depends on what you want to do with your plugin. I haven’t included all these methods because I’m only interested in some of them, I use:

- Paint
I use the function for showing the current state of the player. At the moment there are two states only: VLC is not running and VLC is running. This method shows the right icon for the current plugin state, nothing more.

BOOL __stdcall Paint(HDC hdc)
{
// VLC is running?
if ((FindWindow(NULL, “VLC media player”)))
{
// VLC is running, do I have to display the new icon state?
if (!running)
{
DoPaint(hdc, IDI_PLAY); // Show the new icon
running = TRUE;
return TRUE;
}
}
else
{
// VLC is not running, do I have to display the new icon state?
if (running)
{
DoPaint(hdc, IDI_NO_VLC); // Show the new icon
running = FALSE;
return TRUE;
}
}

return FALSE;
}

Paint function is called many times and it’s useless to paint the scene everytime. I only let it paint when the state changes, that’s why I use the running member.

- GetInfo

LPARAM __stdcall GetInfo(int index)
{
GET_INFO(INFO_NAME, “VLC player”);
GET_INFO(INFO_DESC, “Simple plugin for VLC player”);
GET_INFO(INFO_AUTHOR, “ZaiRoN”);
GET_INFO(INFO_EMAIL, “zaironcrk@hotmail.com” );
GET_INFO(INFO_HOMEPAGE, “http://www.zairon.wordpress.com&#8221;);
return 0;
}

Some info for the about box…

- OnKeyDown
When the button has been pressed (and VLC is running) I have to play (or pause) the video. How to perform such operation from an external application? I don’t know if VLC has a script engine really. With the engine it could be possible to control the player in an easy way but without it the only way is to use the good old SendMessage method. The idea is to send a specific message to VLC. I’ll tell VLC to play and pause a file using SendMessage. First of all let’s see how SendMessage looks like:

LRESULT SendMessage(
HWND hWnd, // The window designed to receive the message
UINT Msg, // The message to send
WPARAM wParam, // wParam, depends on the message
LPARAM lParam // lParam, depends on the message
);

To find out the handle of VLC window is pretty easy, just use FindWindow as I did in Paint function.
What about the message to send? For this purpose I used Spy++, a little (but very useful) program that comes with Visual Studio pack. The tool shows me the message I was looking for. It’s WM_COMMAND with wParam equal to 0×6020. VLC uses the same wParam for both play/pause commands. Here is how my OnKeyDown function looks like:

void __stdcall OnKeyDown()
{
HWND hVLC = NULL;

// Message is sent if and only if VLC is running
if ((hVLC = FindWindow(NULL, “VLC media player”)))
PostMessage(hVLC, WM_COMMAND, 6020, 0); // Start/Pause command
}

Believe it or not this is the core of the plugin! Few lines of code and voilà, the plugin is done.

The plugin is really simple but as you can see it’s really easy to develop a plugin… just use some imagination.
Attached here the source code of the project (About the two icons, they are simply horrible I know… I’m not a graphic designer).

Next Page »

Follow

Get every new post delivered to your Inbox.