📜 ⬆️ ⬇️

Magic Ctrl-C Ctrl-V, or how to stop saving pictures and start living

image

One of the few standard Windows utilities that I use almost every day is snippingtool , or, simply speaking, Scissors. It performs its task with a bang (however, I don’t need much from it), and among other useful things, you can mark the insertion of the selected region directly into Skype, without having to save the image to a file - just press Ctrl-V in the message input window. It's nice that the name of the file in this case will consist of the date and time instead of, for example, a hash.

Despite the fact that in the Snipping Tool it is possible to trace certain parts of the image, sometimes this is not enough:
')

It is for these reasons that I often refer to mspaint . But he has a reverse flaw - paste the image directly from the clipboard in Skype will not work.

What is the reason for this behavior? Can I fix it? Let's figure it out.

How was the process, and what came of it, read under the cut.

I suggest starting with comparing the contents of the clipboard in case of copying an image from snippingtool and from mspaint. To do this, you can use a program called InsideClipboard . Download, unzip and run InsideClipboard, open Scissors (Win-R -> snippingtool), select a region (in my case it is a small part of the black background on the desktop), click F5 on InsideClipboard and see the following picture:

image

Save the same image somewhere to disk, open it in mspaint (Win-R -> mspaint), select it completely (Select -> Select all), copy to the clipboard using Ctrl-C, update the state InsideClipboard again and see what happened on the clipboard this time:

image

In addition to the bitmap itself, in this case we can observe some additional information in the clipboard. Maybe it was she who interferes with Skype when inserting an image?

Since A self-proprietary protection was attached to the Skype client; for this task, it would be much easier to use some WinAPI function interceptor to see how Skype “looks” into the clipboard. Download and run WinAPIOverride , specify Skype PID in the “Process ID” field and click on the “Start” button:

image

Great, click on the button "Monitoring Files Library"

image

and start ticking next to the functions associated with working with the clipboard. A complete list of them can be found , for example, on MSDN:

AddClipboardFormatListener
ChangeClipboardChain
CloseClipboard
CountClipboardFormats
EmptyClipboard
EnumClipboardFormats
GetClipboarddata
GetClipboardFormatName
GetClipboardOwner
GetClipboardSequenceNumber
GetClipboardViewer
GetOpenClipboardWindow
GetPriorityClipboardFormat
GetUpdatedClipboardFormats
IsClipboardFormatAvailable
Openclipboard
RegisterClipboardFormat
RemoveClipboardFormatListener
SetClipboardData
SetClipboardViewer

Go to the documentation for any of them and note that the work with the clipboard is carried out using the User32 module. Put a tick next to it and the corresponding functions and click on the “OK” button:

image

Insert an image from the snippingtool into the Skype message input window and look at the call chain:

image

Now do the same with mspaint:

image

Notice that the IsClipboardFormatAvailable function, called with argument 0x0000C013, returns different results in the two cases we have considered. This argument indicates the format, the presence of which, in fact, you want to check:

format [in]
Type: UINT
A standard or registered clipboard format. For a description of the standard clipboard formats, see Standard Clipboard Formats

Let's take a look at the definition of predefined formats in the WinUser.h header file:

/* * Predefined Clipboard Formats */ #define CF_TEXT 1 #define CF_BITMAP 2 #define CF_METAFILEPICT 3 #define CF_SYLK 4 #define CF_DIF 5 #define CF_TIFF 6 #define CF_OEMTEXT 7 #define CF_DIB 8 #define CF_PALETTE 9 #define CF_PENDATA 10 #define CF_RIFF 11 #define CF_WAVE 12 #define CF_UNICODETEXT 13 #define CF_ENHMETAFILE 14 #if(WINVER >= 0x0400) #define CF_HDROP 15 #define CF_LOCALE 16 #endif /* WINVER >= 0x0400 */ #if(WINVER >= 0x0500) #define CF_DIBV5 17 #endif /* WINVER >= 0x0500 */ #if(WINVER >= 0x0500) #define CF_MAX 18 #elif(WINVER >= 0x0400) #define CF_MAX 17 #else #define CF_MAX 15 #endif #define CF_OWNERDISPLAY 0x0080 #define CF_DSPTEXT 0x0081 #define CF_DSPBITMAP 0x0082 #define CF_DSPMETAFILEPICT 0x0083 #define CF_DSPENHMETAFILE 0x008E /* * "Private" formats don't get GlobalFree()'d */ #define CF_PRIVATEFIRST 0x0200 #define CF_PRIVATELAST 0x02FF /* * "GDIOBJ" formats do get DeleteObject()'d */ #define CF_GDIOBJFIRST 0x0300 #define CF_GDIOBJLAST 0x03FF 

As you can see, 0x0000C013 that interests us is, unfortunately, not among them. Googling a bit, I came across several sources (for example, here ), which say that this format is associated with OLE :

The Windows clipboard is the mechanism that Microsoft
Windows operating systems
between applications. It first appeared in Windows 3.1,
although its functionality has greatly increased since then.
Table 1 shows the standard formats used by the clipboard
(Petzold, 1999). However, Microsoft also provides the ability
for “private data formats”, formats that are application
specific (for example, fonts in a word processing program),
couldn’t have been registered
transfer data in these formats (Petzold, 1999). Two private data
formats that are used extensively are object link embedding
(OLE) (0xC013) and dataobjects (0xC009)

If we load mspaint into OllyDbg and set the breakpoint at the beginning of the SetClipboardData function, then when copying the image or its part to the clipboard, we will see by Call Stack that we were really called from OLE-related functions:

image

Apparently, Skype is really at a meeting in the clipboard data associated with OLE, ceases to think that it is a full image. I can not say whether this is a bug or a feature, but this behavior obviously does not suit me.

By the way, did you notice that InsideClipboard did not show data with the format 0x0000C013? If you download any other viewer clipboard (for example, Free Clipboard Viewer ), then we will see these “Ole Private Data”:

image

But wait! After all, there really is an image in the clipboard, since we can copy it, for example, on the same mspaint. Let's try to get it, clear the current contents of the clipboard and “compose” it again, so that there is not the slightest mention of OLE in it.

We write the following code in C #

 using System; using System.Windows.Forms; namespace clipboard_helper { class Program { [STAThread] static void Main(string[] args) { if (Clipboard.ContainsData(DataFormats.Bitmap)) { object data = Clipboard.GetData(DataFormats.Bitmap); Clipboard.SetData(DataFormats.Dib, data); } } } } 

copy the image from mspaint to the clipboard, look at the output of InsideClipboard

image

, run our application and look at the contents of the clipboard again:

image

We try to insert the image in Skype, and ...

image

Great!

Of course, manually launching a separate executable file every time you copy is not a good idea, so I suggest that you arm yourself with OllyDbg and start doing it automatically. Yes, you can call the appropriate code directly from the OllyDbg module, but why, if we already have a ready-made program?

Copy mspaint.exe from "% WINDIR% \ System32" to any other directory, remove the use of ASLR technology using PE Tools (this process has already been described several times in previous articles - for example, here ), run Paint in OllyDbg and see the following message :

image

Well, we have previously dealt with changing the behavior of the application in the event of a change in its environment, so let's create a directory called “en-US” (in your case, of course, it can be different), and put the mspaint.exe file there. mui.

Yes, now Paint starts correctly:

image

Go to the User32 module (right-click on the window CPU -> View -> Module 'USER32'), press Ctrl-N and look for SetClipboardData in the list of names:

image

Put the breakpoint on the beginning of this function, copy something to the clipboard from the mspaint window and look at the call stack:

image

We jump to the nearest "user" code, which in this case is located at 0x104FDE3 , and look at the "environment":

image

Ok, at the address 0x0104FDE8 you can position the jump on our code cave. Let's think about how it will look like:

 ;      PUSHAD PUSHFD ;   ShellExecuteA PUSH 0 ; nShowCmd PUSH 0 ; lpDirectory PUSH 0 ; lpParameters PUSH "cb_helper.exe" ; lpFile PUSH "open" ; lpOperation PUSH 0 ; hwnd CALL ShellExecuteA ;     ""  POPFD POPAD ;  ,       code cave' MOV EAX,DWORD PTR DS:[ESI] PUSH EDI MOV ECX,ESI JMP 0x0104FDFD 

Now you need to know the address in the IAT, which is the address of the ShellExecuteA function. We load mspaint.exe into PE Tools, click on the “Directories” button, open the “Import Directory” item and click on SHELL32.dll (exactly there, according to the documentation, the implementation of this function is found):

image

Unfortunately, among the functions imported from SHELL32.dll there is neither the ShellExecute name, nor CreateProcess , nor the system (however, there is an import of the ShellExecuteExW function, but in our case it is somewhat redundant). Maybe it is imported by ordinal?

image

Let's find out which ordinal corresponds to it. To solve this problem, I used the dumpbin utility, available from VS Command Prompt:

 dumpbin / exports shell32.dll

 Microsoft (R) COFF / PE Dumper Version 11.00.60610.1
 Copyright (C) Microsoft Corporation.  All rights reserved.


 Dump of file shell32.dll

 File Type: DLL

   Section contains the following exports for SHELL32.dll

     00000000 characteristics
     505A94F2 time date stamp Thu Sep 20 08:00:50 2012
         0.00 version
            2 ordinal base
          930 number of functions
          349 number of names

     ordinal hint RVA name
         [...]
         451 12E 0027CF17 ShellExecuteA
         452 12F 0027CFA0 ShellExecuteEx
         453 130 0027CFA0 ShellExecuteExA
         454 131 0006CD23 ShellExecuteExW
         455 132 001F8CAB ShellExecuteW

As you can see, it cannot be imported by the ordinal either.

Well, then we have the following options:

The first solution will turn into approximately the same problem that we are dealing with right now - none of the WinAPI functions required to work with the clipboard are currently directly imported into the application under study. Interaction with the clipboard is carried out through OLE, which, in my opinion, is not the most convenient option for patching.
The second solution will work, however, in my opinion, does not look very elegant.
But the third solution looks pretty tempting.

To add a new feature to IAT, I decided to use a program called CFF Explorer, part of the Explorer Suite . Open mspaint.exe in it, go to the “Import Adder” tab, click on the “Add” button, specify the path to the shell32.dll file ("% WINDIR% \ System32 \ shell32.dll"), select the ShellExecuteA function from the list that appears click on the “Import By Name” and “Rebuild Import Table” buttons, then save the changes:

image

As a result of our actions in the Import Directory tab of the same tool, the following entry should appear:

image

Strange, but the execution of these steps led to different results on different versions of Windows. As a result of doing these operations on Windows 7, we get a binary that contains instead of the address of the ShellExecuteA function some kind of nonsense, but if you perform all these actions on Windows XP, then everything works as expected. At the time of this writing, I was in the process of communicating with the user - = AkaBOSS = - with exelab to find out the reason for this behavior.

Taking the binary from the CFF Explorer program on Windows XP, I opened it on my main system in OllyDbg and looked at the address 0x01617198 . Why this particular address? Because the mspaint module was loaded at 0x01000000 (however, it could not be loaded on any other database, because we have disabled ASLR earlier)

image

, and CFF Explorer told us to look at the offset 0x00617198 . 0x01000000 + 0x00617198 = 0x01617198 .

image

As you can see, the address of the ShellExecuteA function is indeed located here.

We are looking for a place for code cave and write the following code (of course, addresses may differ):

 0108977D . 6F 70 65 6E 00 ASCII "open",0 01089782 . 63 62 5F 68 65 6C 70 65 72 2E 65 78 65 00 ASCII "cb_helper.exe",0 01089790 > 60 PUSHAD 01089791 . 9C PUSHFD 01089792 . 6A 00 PUSH 0 ; /IsShown = 0 01089794 . 6A 00 PUSH 0 ; |DefDir = NULL 01089796 . 6A 00 PUSH 0 ; |Parameters = NULL 01089798 . 68 82970801 PUSH mspaint.01089782 ; |FileName = "cb_helper.exe" 0108979D . 68 7D970801 PUSH mspaint.0108977D ; |Operation = "open" 010897A2 . 6A 00 PUSH 0 ; |hWnd = NULL 010897A4 . FF15 98716101 CALL DWORD PTR DS:[<&shell32.ShellExecuteA>] ; \ShellExecuteA 010897AA . 9D POPFD 010897AB . 61 POPAD 010897AC . 8B06 MOV EAX,DWORD PTR DS:[ESI] 010897AE . 57 PUSH EDI 010897AF . 8BCE MOV ECX,ESI 010897B1 .^ E9 4766FCFF JMP mspaint.0104FDFD 

Now add a jump to our code cave after calling the procedure responsible for adding data to the clipboard:

 0104FDE3 . E8 B6A70100 CALL <JMP.&MFC42u.#2066> 0104FDE8 . E9 A3990300 JMP mspaint.01089790 0104FDED . EB 0E JMP SHORT mspaint.0104FDFD 

We save our changes to the executable file and enjoy directly pasting the contents of the clipboard from mspaint to Skype.

Afterword


It's time to say goodbye to the files "2.PNG" and "3.PNG" from the creators of "1.PNG", who just wanted to send images to their interlocutors in Skype. Do not be lazy to come up with random names for your files? Then do not be lazy and open OllyDbg.

Thank you for your attention, and again I hope that the article was useful to someone.

Source: https://habr.com/ru/post/263175/


All Articles