views:

331

answers:

1

I want to call SHFileOperation using code injection. My code works fine while calling simple functions like MessageBox from user32.dll, but won't while calling ShFileOperation from shell32.dll.

I'll post the part of the code that I think has the problem. I know the problem is in the struct implementation.

Here is the image of RemoteInfo value:

http://www.freeimagehosting.net/uploads/219d79fc30.jpg

//Structure
type
  LPSHFILEOPSTRUCT = ^SHFILEOPSTRUCT;
  SHFILEOPSTRUCT = packed record
    Wnd: HWND;
    wFunc: UINT;
    pFrom: PAnsiChar;
    pTo: PAnsiChar;
    fFlags: FILEOP_FLAGS;
    fAnyOperationsAborted: BOOL;
    hNameMappings: Pointer;
    lpszProgressTitle: PAnsiChar;
  end;

//Remote Info
type
  TRemoteInfo = record
    LoadLibrary: function(lpLibFileName: PChar): HMODULE; stdcall;
    GetProcAddress: function(hModule: HMODULE;
      lpProcName: LPCSTR): FARPROC; stdcall;
    shf: SHFILEOPSTRUCT; ;
    Kernel32: array[0..20] of Char;
    shell32: array[0..20] of Char;
    SHFileOperationA: array[0..20] of Char;
    Fromlpbuff: array[0..20] of char; //Source path
    Tolpbuff: array[0..20] of Char;   //Des Path
  end;

//Initialize                      
                      ....
ZeroMemory(@RemoteInfo, SizeOf(RemoteInfo));
  RemoteInfo.shf.Wnd := 0;
  RemoteInfo.shf.wFunc := FO_COPY;
  RemoteInfo.shf.pFrom := @remoteInfo.Fromlpbuff;
  RemoteInfo.shf.pto := @remoteInfo.tolpbuff;
  lstrcpy(RemoteInfo.shf.pFrom, 'e:\1.jpg' + #0#0);
  lstrcpy(RemoteInfo.shf.pto, 'f:\1.jpg' + #0#0);
  RemoteInfo.shf.fFlags := FOF_ALLOWUNDO;
  RemoteInfo.shf.fAnyOperationsAborted := false;
                      ....
A: 

The immediate problem in this code is that you're storing pointers to the string parameters in your record. Those pointers are addresses in your main process; they are not valid in the target process. You should store those values in fixed-size arrays in your record, just like you're already doing with the module and function names. Then initialize the pointer fields inside the remote function.

But you're really making it more complicated than it needs to be. You don't need to use GetProcAddress in the remote function at all. Put you entire function in a DLL. There you can call whatever functions you want, and the Delphi linker and the OS loader will ensure that they're all available to call at run time. You also don't need to allocate all your variables with VirtualAllocEx; you can use ordinary local variables in your DLL function.

You'll use CreateRemoteThread three times over the course of your program. The first time is to inject a call to LoadLibrary to get your DLL into the target process's address space. The second time is to invoke your injected function, and the third time is to call FreeLibrary after you're finished. The tricky part is finding the address of your injected function in the target process. Alexey Kurakin's article on Code Project demonstrates how to do that by finding the relative address of the function in your own process, and the applying that offset to the remote process to determine the argument to pass to your second call to CreateRemoteThread.

Finally, there's no need to declare the support records for ShFileOperation yourself. Delphi already declares them for you in the ShellAPI unit. There you'll also find the named constants for the various flags you need, like fo_Copy instead of $0002.

Rob Kennedy
thx MR kennedy but i want to do this by declare the struct by my self i'm making some changes i'll post it
sam
If you change the definition of the struct, then it's no longer compatible with what ShFileOperation expects to receive. You don't get to negotiate with the API. When the API says a field is a pointer, you need to provide a pointer, not an array. The API function is going to take that value and treat it like a pointer by dereferencing it to read the characters it points to. Or are you also rewriting ShFileOperation?
Rob Kennedy
I know the definition should be same as the api,but when i use pointer instead of array, the path won't be in correct format, i don't know how to make the result as the image while using pointer instead of array?!!!
sam
I see. You're concerned because when you have an ordinary PChar field, the *debugger* doesn't display the null characters at the end of the strings. That's because the *debugger* doesn't know that the character pointer you're inspecting is treated specially. The debugger just treats it the same as it treats all other character-pointer types: It displays the characters until it reaches a null character. Just because it doesn't show you the null characters at the end doesn't mean they aren't there. Please refer to any of the hundreds of examples available demonstrating ShFileOperation in Delphi.
Rob Kennedy
the above code and the image is now edited again
sam
I don't know what should i do with this,the api doesn't accept the paths
sam
in the new image the format of "pto" and "pfrom" is not correct,it should be like "fromlpbuff" and "tolpbuff"
sam
As I *just* told you, that's the way the debugger *displays* character pointers, including `pFrom` and `pTo`. The debugger does not display the null characters at the ends of those strings, but you should not interpret *that* as evidence that the null characters aren't there. The debugger simply doesn't show them to you. But actually, you're only guaranteed that *one* is there. The `lstrcpy` function stops after the first null character. The rest are null because you used `ZeroMemory` earlier. To copy the nulls at the end of a string, use `StrPLCopy` instead.
Rob Kennedy
The code *can* be used in a remote process. Put all your code in a DLL. Load the DLL in the remote process. Call your DLL function in the remote process. The link I gave shows how to do that. Put your string argument in the array with StrPLCopy. Copy the array into the remote process's address space. In the DLL, simply assign the array to the pointer parameter: `shf.pFrom := PRemoteInfo(Param).Fromlpbuff;`
Rob Kennedy
thx for ur time ROB
sam