内核中插APC启动用户程序问题

scw121 2009-06-30 02:23:04
#include "Process.h"

typedef enum
{
OriginalApcEnvironment,
AttachedApcEnvironment,
CurrentApcEnvironment
} KAPC_ENVIRONMENT;

void ApcKernelRoutine( IN struct _KAPC *Apc, IN OUT PKNORMAL_ROUTINE *NormalRoutine, IN OUT PVOID *NormalContext, IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2 ) ;
NTSTATUS InstallUserModeApc(LPSTR lpProcess, PKTHREAD pTargetThread, PEPROCESS pTargetProcess);
void ApcCreateProcess(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2);
void ApcCreateProcessEnd();
#pragma alloc_text(PAGE, RunProcess)
#pragma alloc_text(PAGE, ApcKernelRoutine)
#pragma alloc_text(PAGE, InstallUserModeApc)
#pragma alloc_text(PAGE, ApcCreateProcess)
#pragma alloc_text(PAGE, ApcCreateProcessEnd)

void RunProcess(LPSTR lpProcess)
{

PEPROCESS pTargetProcess = NULL; //self explanatory
PKTHREAD pTargetThread = NULL; //thread that can be either alerable or non-alertable
PKTHREAD pNotAlertableThread = NULL; //non-alertable thread
PEPROCESS pSystemProcess = NULL; //May not necessarily be the 'System' process

PETHREAD pTempThread = NULL;
PLIST_ENTRY pNextEntry, pListHead, pThNextEntry;


if(strlen(lpProcess)>300) return; //name not longer than 300 characters

pSystemProcess = PsGetCurrentProcess(); //make sure you are running at IRQL PASSIVE_LEVEL

if(!pSystemProcess)
{
DbgPrint("KernelExec -> Cannot find 'System' process!");
return;
}

if(IsListEmpty(&pSystemProcess->ActiveProcessLinks))
DbgPrint("KernelExec -> No processes found!");
else
{
pListHead = &pSystemProcess->ActiveProcessLinks;
pNextEntry = pListHead->Flink;

while(pNextEntry != pListHead) //start looping through the available processes
{
pSystemProcess = CONTAINING_RECORD(pNextEntry,EPROCESS,ActiveProcessLinks);

if(pSystemProcess->ActiveThreads)
{
if(!IsListEmpty(&pSystemProcess->ThreadListHead))
{
//Is this explorer.exe?
if(_strnicmp(pSystemProcess->ImageFileName,"explorer.exe",12)==0)
{
pTargetProcess = pSystemProcess; //Yes,we have found it!
pTargetThread = pNotAlertableThread = NULL;

pThNextEntry = pSystemProcess->ThreadListHead.Flink;

//Now we loop through it's threads, seeking an alertable thread
while(pThNextEntry != &pSystemProcess->ThreadListHead)
{
pTempThread = CONTAINING_RECORD(pThNextEntry,ETHREAD,ThreadListEntry);

if(pTempThread->Tcb.Alertable) //Tcb is the KTHREAD of this ETHREAD and stands for 'Thread Control Block'
{
//Good, an alertable thread was found.
pTargetThread = &pTempThread->Tcb;

DbgPrint("KernelExec -> Found alertable thread");
//We will be using this one, so break now
break;
}
else
{
//Didn't find an alertable thread yet, so we'll keep this one
//just in case we won't find ANY alertable threads
pNotAlertableThread = &pTempThread->Tcb;
}

pThNextEntry = pThNextEntry->Flink; //check next thread
}
break;
}
}
}

pSystemProcess = NULL;
pNextEntry = pNextEntry->Flink; //get next process
}
}

if(!pTargetProcess)
{
DbgPrint("KernelExec -> Couldn't find Explorer.exe!");
return;
}

if(!pTargetThread)
{
//No alertable thread was found, so let's hope we've at least got a non-alertable one (we'll set its alertable flag ON)
//There's no problem with non-alertable threads, except for the fact that it takes
//a little longer for them to return from KernelMode. (that means our process execution will be delayed)
pTargetThread = pNotAlertableThread;
}

if(pTargetThread)
{
DbgPrint("KernelExec -> Targeted thread: 0x%p",pTargetThread);
//We have one thread (alertable or n/a), now install the APC
InstallUserModeApc(lpProcess, pTargetThread,pTargetProcess);
}
else
DbgPrint("KernelExec -> No thread found!"); //Explorer exe with NO threads (???)
}



PMDL pMdl = NULL;

void ApcKernelRoutine( IN struct _KAPC *Apc, IN OUT PKNORMAL_ROUTINE *NormalRoutine,
IN OUT PVOID *NormalContext, IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2 )
{

if (Apc)
ExFreePool(Apc);
if(pMdl)
{
MmUnlockPages(pMdl);
IoFreeMdl (pMdl);
pMdl = NULL;
}
DbgPrint("KernelExec -> ApcKernelRoutine called. Memory freed.");
}

NTSTATUS
InstallUserModeApc(LPSTR lpProcess, PKTHREAD pTargetThread, PEPROCESS pTargetProcess)
{
PRKAPC pApc = NULL; //Our APC

PVOID pMappedAddress = NULL; //This is where the UserMode routine's code will be placed at
ULONG dwSize = 0; //Size of code to be executed in Explorer's address space

KAPC_STATE ApcState; // Needed for KeStackAttachProcess

ULONG *data_addr=0; //just a helper to change the address of the 'push' instruction
//in the ApcCreateProcess routine
ULONG dwMappedAddress = 0; //same as above

NTSTATUS Status = STATUS_UNSUCCESSFUL;

if (!pTargetThread || !pTargetProcess)
return STATUS_UNSUCCESSFUL;


//Allocate memory for our APC
pApc = ExAllocatePool (NonPagedPool,sizeof (KAPC));
if (!pApc)
{
DbgPrint("KernelExec -> Failed to allocate memory for the APC structure");
return STATUS_INSUFFICIENT_RESOURCES;
}

//Get the size of our UserMode code
dwSize = (unsigned char*)ApcCreateProcessEnd-(unsigned char*)ApcCreateProcess;
KdPrint(("%d",dwSize));
//Allocate an MDL describing our ApcCreateProcess' memory
pMdl = IoAllocateMdl (ApcCreateProcess, dwSize, FALSE,FALSE,NULL);
if (!pMdl)
{
DbgPrint("KernelExec -> Failed to allocate MDL");
ExFreePool (pApc);
return STATUS_INSUFFICIENT_RESOURCES;
}

__try
{
//Probe the pages for Write access and make them memory resident
MmProbeAndLockPages (pMdl,KernelMode,IoWriteAccess);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("KernelExec -> Exception during MmProbeAndLockPages");
IoFreeMdl (pMdl);
ExFreePool (pApc);
return STATUS_UNSUCCESSFUL;
}

//Attach to the Explorer's address space
KeStackAttachProcess(&(pTargetProcess->Pcb),&ApcState);

//Now map the physical pages (our code) described by 'pMdl'
pMappedAddress = MmMapLockedPagesSpecifyCache (pMdl,UserMode,MmCached,NULL,FALSE,NormalPagePriority);

if (!pMappedAddress)
{
DbgPrint("KernelExec -> Cannot map address");

KeUnstackDetachProcess (&ApcState);
IoFreeMdl (pMdl);
ExFreePool (pApc);

return STATUS_UNSUCCESSFUL;
}
else
DbgPrint("KernelExec -> UserMode memory at address: 0x%p",pMappedAddress);

dwMappedAddress = (ULONG)pMappedAddress;

memset ((unsigned char*)pMappedAddress + 0x14, 0, 300);//zero everything out ecxept our assembler code
memcpy ((unsigned char*)pMappedAddress + 0x14, lpProcess,strlen (lpProcess)); //copy the path to the executable

data_addr = (ULONG*)((char*)pMappedAddress+0x9); //address pushed on the stack (originaly 0xabcd)...
*data_addr = dwMappedAddress+0x14; //..gets changed to point to our exe's path

//all done, detach now
KeUnstackDetachProcess (&ApcState);

//Initialize the APC...
KeInitializeApc(pApc,pTargetThread,
OriginalApcEnvironment,
&ApcKernelRoutine,NULL,
pMappedAddress, UserMode, (PVOID) NULL);

//...and queue it
if (!KeInsertQueueApc(pApc,0,NULL,0))
{
DbgPrint("KernelExec -> Failed to insert APC");
MmUnlockPages(pMdl);
IoFreeMdl (pMdl);
ExFreePool (pApc);
return STATUS_UNSUCCESSFUL;
}
else
{
DbgPrint("KernelExec -> APC delivered");
}

//is this a non-alertable thread?
if(!pTargetThread->ApcState.UserApcPending)
{
//if yes then alert it
pTargetThread->ApcState.UserApcPending = TRUE;
}

return 0;
}

__declspec(naked) void ApcCreateProcess(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
__asm
{
mov eax,0x7C86250D
push 1
nop
push 0xabcd
call eax
jmp end
nop
.
.
这里是300个nop
end:
nop
ret 0x0c
}

}
void ApcCreateProcessEnd(){}

driverentry中 很简单,直接调用runprocess(“c:\cmd.exe”)


#include "KernelExec.h"
#include "Process.h"
#include "ntifs.h"
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
...
RunProcess("C:\\cmd.exe");

return NtStatus;
}


在ApcCreateProcess中用硬编码直接写winexec函数的地址,0x7c86250d是WINXP SP3的,这个有局限性
所以想吧它改为能够动态获取winexec函数地址,以适应其他win2k以上平台,调试通过,但是用户程序却没有启动起来。
以下是修改后的,字数太多,接下面
...全文
566 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
chenhui530 2009-09-14
  • 打赏
  • 举报
回复
楼主是一个只会抄袭的人,鉴定完毕
sleepy722 2009-09-11
  • 打赏
  • 举报
回复
怎么没人解决这个问题,我也急需这个问题的解决啊,有能帮忙的联系我454419771 ,不胜感激啊,谢谢了
hendriclee 2009-07-03
  • 打赏
  • 举报
回复
帮顶,学习
IORI915189 2009-07-03
  • 打赏
  • 举报
回复
R3 getprocaddress 传给R0 系统库函数 在所有进程中 地址都是一样的

ApcCreateProcess函数中 WinExec地址先用一个特定值占位 如 0x11223344
用时 直接搜索ApcCreateProcess 函数 找这个值 替换成R3传递过来的 不就完了


驱动你都能加载了 还怕别人不让你运行EXE? 够无聊的
jingzhongrong 2009-06-30
  • 打赏
  • 举报
回复
attach到一个加载有kernel32.dll的进程中,得到dll的加载地址,根据PE文件格式得到导出表,查找WinExec函数,计算函数的地址。
一般来说,kernel32.dll在各个进程中的加载基址都是一样的。
scw121 2009-06-30
  • 打赏
  • 举报
回复
哈哈,回楼上,我当初也是这么想的,兼容了win xp2和xp3,没想到发布出去时,我差点吐血,因为有很多盗版的windows,像什么深度啊,gost什么的,特别是深度游很多版本,他们的winexec地址根本不一样
skyxie 2009-06-30
  • 打赏
  • 举报
回复
mark 一下, 学习~

给个笨办法: 在OS的每个patch下winexec的地址是固定的~ (win2k, win2ksp4, winxp, sp1, sp2, sp3)反正就那么几个版本,记倒一个数组中,

ApcCreateProcess中判断一下OS的版本, 是哪个版本就用哪个版本的地址...
scw121 2009-06-30
  • 打赏
  • 举报
回复

memset ((unsigned char*)pMappedAddress + 163, 0, 300);//zero everything out ecxept our assembler code
memcpy ((unsigned char*)pMappedAddress + 163, lpProcess,strlen (lpProcess)); //copy the path to the executable

这里的修改是修改上面的,删掉了
data_addr = (ULONG*)((char*)pMappedAddress+0x9);
*data_addr = dwMappedAddress+0x14;这2句

然后 ApcCreateProcess函数改为:

__declspec(naked) void ApcCreateProcess(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
__asm
{
push ebp
mov ebp,esp
push ebx
push esi
push edi
jmp __startup; ; these are just functions.... skip

__find_kernel32:
push esi ; Save esi
push 0x30
pop ecx
mov eax, fs:[ecx] ; Extract the PEB
mov eax, [eax + 0x0c] ; Extract the PROCESS_MODULE_INFO pointer from the PEB
mov esi, [eax + 0x1c] ; Get the address of flink in the init module list
lodsd ; Load the address of blink into eax
mov eax, [eax + 0x8] ; Grab the module base address from the list entry
pop esi ; Restore esi
ret ; Return

__find_function:
pushad ; Save all registers
mov ebp, [esp + 0x24] ; Store the base address in eax
mov eax, [ebp + 0x3c] ; PE header VMA
mov edx, [ebp + eax + 0x78] ; Export table relative offset
add edx, ebp ; Export table VMA
mov ecx, [edx + 0x18] ; Number of names
mov ebx, [edx + 0x20] ; Names table relative offset
add ebx, ebp ; Names table VMA

__find_function_loop:
jecxz __find_function_finished ; Jump to the end if ecx is 0
dec ecx ; Decrement our names counter
mov esi, [ebx + ecx * 4] ; Store the relative offset of the name
add esi, ebp ; Set esi to the VMA of the current name

xor edi, edi ; Zero edi
xor eax, eax ; Zero eax
cld ; Clear direction

__compute_hash_again:
lodsb ; Load the next byte from esi into al
test al, al ; Test ourselves.
jz __compute_hash_finished ; If the ZF is set, we've hit the null term.
ror edi, 0xd ; Rotate edi 13 bits to the right
add edi, eax ; Add the new byte to the accumulator
jmp __compute_hash_again ; Next iteration

__compute_hash_finished:
cmp edi, [esp + 0x28] ; Compare the computed hash with the requested hash
jnz __find_function_loop ; No match, try the next one.
mov ebx, [edx + 0x24] ; Ordinals table relative offset
add ebx, ebp ; Ordinals table VMA
mov cx, [ebx + 2 * ecx] ; Extrapolate the function's ordinal
mov ebx, [edx + 0x1c] ; Address table relative offset
add ebx, ebp ; Address table VMA
mov eax, [ebx + 4 * ecx] ; Extract the relative function offset from its ordinal
add eax, ebp ; Function VMA
mov [esp + 0x1c], eax ; Overwrite stack version of eax from pushad

__find_function_finished:
popad ; Restore all registers
ret 8

__begin:
nop
pop edi ; Pop address
mov ebx, __execute
sub ebx, __command_line
sub edi, ebx ; filename offset
mov esi,edi ; filename to edi
call __find_kernel32 ; Find kernel32 address
mov ebx, eax ; Save address in ebx
jmp short __execute ; Skip data

__startup:
call __begin ; Fetch our data address


__execute:
push 0x0e8afe98 ; WinExec hash
push ebx ; kernel32 base address
call __find_function ; find address

xor ecx,ecx
inc ecx ; ecx = 1
push ecx ; uCmdShow
push esi ; lpCmdLine. We already have the exe path in esi
call eax ; call WinExec
jmp __end

__command_line: ; Space (~300 bytes) for commandline
这里是300个nop
__end:
pop edi ; restore registers
pop esi
pop ebx
pop ebp
ret 0x0c
}


郁闷,代码太多了,估计没人看,能帮忙调试的朋友,留下邮件,吧整个工程发你们,希望能帮帮小弟!谢谢!!
460564@qq.com

15,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧