Quote:
Originally posted by 4oh4
edited to disable the smilies that were fucking up my code
|
Don't you hate those

WORD smiley faces?
Hooking the API aside for the moment, you'd have to take into account the target program may be expecting more than just the VolumeSerialNumber returned it what it *thought* was its own call to GetVolumeInformation. So you fake your own call to fill the buffers the targets API call has already set up, referenced to the stack, and change the one you want.
This code works as an include module under a button or something. Every parameter is included, though your target may actually use NULL for some of them. DupeTarget proc is supposed to be how your patched target behaves, it pushes exactly the same things, but calls your dll function instead.
;================================================
DupeTarget proto
MyGetVolumeInformation proto : DWORD, : DWORD, : DWORD, : DWORD, : DWORD, : DWORD, : DWORD, : DWORD
.DATA
lpRootPathName db "C:\",0
lpVolumeNameBuffer dd 48 dup(?)
nVolumeNameSize DWORD (48)
lpVolumeSerialNumber DWORD ?
lpMaximumComponentLength DWORD ?
lpFileSystemFlags DWORD ?
lpFileSystemNameBuffer dd 48 dup(?)
nFileSystemNameSize DWORD (48)
.CODE
DupeTarget proc
invoke MyGetVolumeInformation, ADDR lpRootPathName, ADDR lpVolumeNameBuffer,\
nVolumeNameSize, ADDR lpVolumeSerialNumber,\
ADDR lpMaximumComponentLength, ADDR lpFileSystemFlags,\
ADDR lpFileSystemNameBuffer, nFileSystemNameSize
ret
DupeTarget endp
MyGetVolumeInformation proc Lprootpathname : Dword, Lpvolumenamebuffer : Dword,\
Nvolumenamesize : Dword, Lpvolumeserialnumber : Dword,\
Lpmaximumcomponentlength : Dword, Lpfilesystemflags : Dword,\
Lpfilesystemnamebuffer : Dword, Nfilesystemnamesize : Dword
invoke GetVolumeInformation, Lprootpathname, Lpvolumenamebuffer,\
Nvolumenamesize, Lpvolumeserialnumber,\
Lpmaximumcomponentlength, Lpfilesystemflags,\
Lpfilesystemnamebuffer, Nfilesystemnamesize
.if (eax)
PUSH eax ; save return value in case program uses GetLastError
push [ebp+14h]
pop eax ; push/pop frame pointer to 4th parameter into eax
mov eax, [eax] ; returned lpVolumeSerialNumber value
xor eax, 0A881A6DEh ; this creates DEADBEEF on my system ;-)
lea ebx, [ebp+14h] ; pointer to the lpVolumeSerialNumber pointer
mov ebx, [ebx] ; lpVolumeSerialNumber pointer
mov dword ptr [ebx], eax ; mov modified value into lpVolumeSerialNumber address
POP eax ; restore true return value
.endif
ret
MyGetVolumeInformation endp
;===============================================
Disassembly:
DupeTarget proc
0167:10001000 FF35CD4A0010 PUSH DWORD PTR [10004ACD]
0167:10001006 680D4A0010 PUSH 10004A0D
0167:1000100B 68094A0010 PUSH 10004A09
0167:10001010 68054A0010 PUSH 10004A05
0167:10001015 68014A0010 PUSH 10004A01 ; ADDR lpVolumeSerialNumber
0167:1000101A FF35FD490010 PUSH DWORD PTR [100049FD]
0167:10001020 683D490010 PUSH 1000493D
0167:10001025 6839490010 PUSH 10004939
0167:1000102A E801000000 CALL 10001030
0167:1000102F C3 RET
MyGetVolumeInformation proc
0167:10001030 55 PUSH EBP
0167:10001031 8BEC MOV EBP,ESP
0167:10001033 FF7524 PUSH DWORD PTR [EBP+24]
0167:10001036 FF7520 PUSH DWORD PTR [EBP+20]
0167:10001039 FF751C PUSH DWORD PTR [EBP+1C]
0167:1000103C FF7518 PUSH DWORD PTR [EBP+18]
0167:1000103F FF7514 PUSH DWORD PTR [EBP+14] ; Lpvolumeserialnumber
0167:10001042 FF7510 PUSH DWORD PTR [EBP+10]
0167:10001045 FF750C PUSH DWORD PTR [EBP+0C]
0167:10001048 FF7508 PUSH DWORD PTR [EBP+08]
0167:1000104B E8721A0000 CALL KERNEL32!GetVolumeInformationA
0167:10001050 0BC0 OR EAX,EAX
0167:10001052 7414 JZ 10001068
0167:10001054 50 PUSH EAX
0167:10001055 FF7514 PUSH DWORD PTR [EBP+14]
0167:10001058 58 POP EAX
0167:10001059 8B00 MOV EAX,[EAX]
0167:1000105B 35DEA681A8 XOR EAX,A881A6DE
0167:10001060 8D5D14 LEA EBX,[EBP+14]
0167:10001063 8B1B MOV EBX,[EBX]
0167:10001065 8903 MOV [EBX],EAX
0167:10001067 58 POP EAX
0167:10001068 C9 LEAVE
0167:10001069 C22000 RET 0020
==========================================
I guess you could implement your loader in various ways, walk the import directory of the target and find the jump table address to GetVolumeInformationA and patch it with your function, or maybe use GetProcAddress to find your kernels address and search for that hex string in the targets memory and patch it as bytes. Being packed makes it a bit of a bother, else you could simply inline patch in some dll loading code. You've got all the ideas for the loader right, I'm not sure about the exact IAT patching details myself.
Cheers,
Kayaker