首页
社区
课程
招聘
[原创][网上其他版本都有BUG]32位程序调用64位程序。X64CALL。读写。远程线程等
发表于: 2016-12-22 14:04 9712

[原创][网上其他版本都有BUG]32位程序调用64位程序。X64CALL。读写。远程线程等

2016-12-22 14:04
9712

索引
1.前言和说明
2.源码
3.核心call的汇编源

前言和说明
  编程和逆向是很多年前的业余爱好,已经有几年不折腾这个领域了。
近来有个小朋友不停问我要这个东西,正好最近回了躺有这台老机器的房子。干脆直接发出来好了。

1.关于x64call的出处:wow64ext  (有需要自行百度)
互联网上其他版本都是在这个基础上改的,
所以都会有跑奔溃的BUG

原因在于:
核心call的实现,
只要是依赖va_start去实现参数入栈,
//va_list args;
//va_start(args, argC);
最终在二进制层都是以编译器编译的帧指针去访问参数,

那么进入x64模式后,
帧指针的高32位很可能在运行过程中不为0,
32位编译出来的程序根本不会考虑 高32位的存在,
一旦不为0,访问参数时就会读到 错误的地址去。


所以解决问题的办法就是直接汇编去实现X64call,全程确保帧指针高位为0.

顺带说一下。
3楼的汇编源码 其实也是一个很具体的win64汇编调用过程的教程。


还有一个很有意思的事是...64位系统本质上没有所谓的32位进程,
如果在主程序放32位DLL里,用一个64位LOADER让它跑起来(或者反之)
所有的调试器都是逗B状态,任何中断被调试器接受都会永远的中断死循环。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 1
支持
分享
最新回复 (7)
雪    币: 118
活跃值: (27)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
//code by the.night

#ifndef _MSC_VER //GCC

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type"    //临时关闭无返回值的警告
#define FORCE_NO_INLINE __attribute__((noinline))//GCC_禁止内联展开程序

FORCE_NO_INLINE
DWORD64 X64Call(DWORD64 func,int argC, ...)
{//后面的参数必须都是DWORD64型.
    asm(".byte 85,137,229,106,51,232,0,0,0,0,131,4,36,5,203,72,99,237,102,129,228,240,255,139,69,16,133,192,116,63,72,139,77,20,131,232,1,133,192,116,52,72,139,85,28,131,232,1,133,192,116,41,76,139,69,36,131,232,1,133,192,116,30,76,139,77,44,131,232,1,133,192,116,19,168,1,117,3,131,236,8,72,255,116,197,44,131,232,1,133,192,117,244,131,236,32,255,85,8,72,137,194,72,193,234,32,232,0,0,0,0,199,68,36,4,35,0,0,0,131,4,36,13,203,201,195;");
}

FORCE_NO_INLINE
DWORD64 x64proc_GetProcAddress64(DWORD64 hModule,const char* lpProcName)
{//x64的程序..c编译后.用调试工具提取的shellcode..只能用X64Call调用它
    asm(".byte 87,86,83,49,192,102,129,57,77,90,117,113,76,99,65,60,73,1,200,65,129,56,80,69,0,0,117,97,69,139,128,136,0,0,0,69,133,192,116,85,74,141,60,1,68,139,71,32,139,119,20,133,246,78,141,20,1,116,66,15,182,26,69,49,219,69,139,10,73,1,201,65,56,25,117,34,132,219,116,49,72,137,208,235,5,69,132,192,116,39,72,131,192,1,73,137,192,73,41,208,71,15,182,4,8,68,58,0,116,231,65,131,195,1,73,131,194,4,65,57,243,117,198,49,192,91,94,95,195,68,57,222,116,245,139,87,36,78,141,4,89,139,71,28,65,15,183,20,16,72,141,20,145,139,4,2,72,1,200,91,94,95,195");
}

FORCE_NO_INLINE
DWORD64 x64proc_GetModuleHandle64(const wchar_t * lpModuleName)
{//x64的程序..c编译后.用调试工具提取的shellcode..只能用X64Call调用它
    asm(".byte 86,83,101,72,139,4,37,96,0,0,0,72,139,64,24,72,139,88,16,72,141,112,16,72,57,222,116,88,15,31,64,0,76,139,75,96,73,137,200,235,11,15,31,128,0,0,0,0,57,208,117,52,73,131,193,2,65,15,183,65,254,68,141,80,191,141,80,32,65,131,250,25,15,70,194,73,131,192,2,65,15,183,80,254,68,141,90,191,68,141,82,32,65,131,251,25,65,15,70,210,133,192,117,200,57,208,116,13,72,139,27,72,57,222,117,172,49,192,91,94,195,72,139,67,48,91,94,195");
}
#pragma GCC diagnostic pop //临时关闭无返回值的警告


#else //ifndef _MSC_VER
#define NAKED __declspec(naked) //VC裸函数

NAKED
DWORD64 X64Call(DWORD64 func,int argC, ...)
{//后面的参数必须都是DWORD64类型
    __asm {
        _emit 0x55;_emit 0x89;_emit 0xE5;_emit 0x6A;_emit 0x33;_emit 0xE8;_emit 0x00;_emit 0x00;_emit 0x00;_emit 0x00;_emit 0x83;_emit 0x04;_emit 0x24;_emit 0x05;_emit 0xCB;_emit 0x48;_emit 0x63;_emit 0xED;_emit 0x66;_emit 0x81;_emit 0xE4;_emit 0xF0;_emit 0xFF;_emit 0x8B;_emit 0x45;_emit 0x10;_emit 0x85;_emit 0xC0;_emit 0x74;_emit 0x3F;_emit 0x48;_emit 0x8B;_emit 0x4D;_emit 0x14;_emit 0x83;_emit 0xE8;_emit 0x01;_emit 0x85;_emit 0xC0;_emit 0x74;_emit 0x34;_emit 0x48;_emit 0x8B;_emit 0x55;_emit 0x1C;_emit 0x83;_emit 0xE8;_emit 0x01;_emit 0x85;_emit 0xC0;_emit 0x74;_emit 0x29;_emit 0x4C;_emit 0x8B;_emit 0x45;_emit 0x24;_emit 0x83;_emit 0xE8;_emit 0x01;_emit 0x85;_emit 0xC0;_emit 0x74;_emit 0x1E;_emit 0x4C;_emit 0x8B;_emit 0x4D;_emit 0x2C;_emit 0x83;_emit 0xE8;_emit 0x01;_emit 0x85;_emit 0xC0;_emit 0x74;_emit 0x13;_emit 0xA8;_emit 0x01;_emit 0x75;_emit 0x03;_emit 0x83;_emit 0xEC;_emit 0x08;_emit 0x48;_emit 0xFF;_emit 0x74;_emit 0xC5;_emit 0x2C;_emit 0x83;_emit 0xE8;_emit 0x01;_emit 0x85;_emit 0xC0;_emit 0x75;_emit 0xF4;_emit 0x83;_emit 0xEC;_emit 0x20;_emit 0xFF;_emit 0x55;_emit 0x08;_emit 0x48;_emit 0x89;_emit 0xC2;_emit 0x48;_emit 0xC1;_emit 0xEA;_emit 0x20;_emit 0xE8;_emit 0x00;_emit 0x00;_emit 0x00;_emit 0x00;_emit 0xC7;_emit 0x44;_emit 0x24;_emit 0x04;_emit 0x23;_emit 0x00;_emit 0x00;_emit 0x00;_emit 0x83;_emit 0x04;_emit 0x24;_emit 0x0D;_emit 0xCB;_emit 0xC9;_emit 0xC3
    };
}

NAKED
DWORD64 x64proc_GetProcAddress64(DWORD64 hModule,const char* lpProcName)
{//x64的程序..c编译后.用调试工具提取的shellcode..只能用X64Call调用它
    __asm {
        _emit 0x57;_emit 0x56;_emit 0x53;_emit 0x31;_emit 0xC0;_emit 0x66;_emit 0x81;_emit 0x39;_emit 0x4D;_emit 0x5A;_emit 0x75;_emit 0x71;_emit 0x4C;_emit 0x63;_emit 0x41;_emit 0x3C;_emit 0x49;_emit 0x01;_emit 0xC8;_emit 0x41;_emit 0x81;_emit 0x38;_emit 0x50;_emit 0x45;_emit 0x00;_emit 0x00;_emit 0x75;_emit 0x61;_emit 0x45;_emit 0x8B;_emit 0x80;_emit 0x88;_emit 0x00;_emit 0x00;_emit 0x00;_emit 0x45;_emit 0x85;_emit 0xC0;_emit 0x74;_emit 0x55;_emit 0x4A;_emit 0x8D;_emit 0x3C;_emit 0x01;_emit 0x44;_emit 0x8B;_emit 0x47;_emit 0x20;_emit 0x8B;_emit 0x77;_emit 0x14;_emit 0x85;_emit 0xF6;_emit 0x4E;_emit 0x8D;_emit 0x14;_emit 0x01;_emit 0x74;_emit 0x42;_emit 0x0F;_emit 0xB6;_emit 0x1A;_emit 0x45;_emit 0x31;_emit 0xDB;_emit 0x45;_emit 0x8B;_emit 0x0A;_emit 0x49;_emit 0x01;_emit 0xC9;_emit 0x41;_emit 0x38;_emit 0x19;_emit 0x75;_emit 0x22;_emit 0x84;_emit 0xDB;_emit 0x74;_emit 0x31;_emit 0x48;_emit 0x89;_emit 0xD0;_emit 0xEB;_emit 0x05;_emit 0x45;_emit 0x84;_emit 0xC0;_emit 0x74;_emit 0x27;_emit 0x48;_emit 0x83;_emit 0xC0;_emit 0x01;_emit 0x49;_emit 0x89;_emit 0xC0;_emit 0x49;_emit 0x29;_emit 0xD0;_emit 0x47;_emit 0x0F;_emit 0xB6;_emit 0x04;_emit 0x08;_emit 0x44;_emit 0x3A;_emit 0x00;_emit 0x74;_emit 0xE7;_emit 0x41;_emit 0x83;_emit 0xC3;_emit 0x01;_emit 0x49;_emit 0x83;_emit 0xC2;_emit 0x04;_emit 0x41;_emit 0x39;_emit 0xF3;_emit 0x75;_emit 0xC6;_emit 0x31;_emit 0xC0;_emit 0x5B;_emit 0x5E;_emit 0x5F;_emit 0xC3;_emit 0x44;_emit 0x39;_emit 0xDE;_emit 0x74;_emit 0xF5;_emit 0x8B;_emit 0x57;_emit 0x24;_emit 0x4E;_emit 0x8D;_emit 0x04;_emit 0x59;_emit 0x8B;_emit 0x47;_emit 0x1C;_emit 0x41;_emit 0x0F;_emit 0xB7;_emit 0x14;_emit 0x10;_emit 0x48;_emit 0x8D;_emit 0x14;_emit 0x91;_emit 0x8B;_emit 0x04;_emit 0x02;_emit 0x48;_emit 0x01;_emit 0xC8;_emit 0x5B;_emit 0x5E;_emit 0x5F;_emit 0xC3
    };
}

NAKED
DWORD64 x64proc_GetModuleHandle64(const wchar_t * lpModuleName)
{//x64的程序..c编译后.用调试工具提取的shellcode..只能用X64Call调用它
    __asm {
        _emit 0x56;_emit 0x53;_emit 0x65;_emit 0x48;_emit 0x8B;_emit 0x04;_emit 0x25;_emit 0x60;_emit 0x00;_emit 0x00;_emit 0x00;_emit 0x48;_emit 0x8B;_emit 0x40;_emit 0x18;_emit 0x48;_emit 0x8B;_emit 0x58;_emit 0x10;_emit 0x48;_emit 0x8D;_emit 0x70;_emit 0x10;_emit 0x48;_emit 0x39;_emit 0xDE;_emit 0x74;_emit 0x58;_emit 0x0F;_emit 0x1F;_emit 0x40;_emit 0x00;_emit 0x4C;_emit 0x8B;_emit 0x4B;_emit 0x60;_emit 0x49;_emit 0x89;_emit 0xC8;_emit 0xEB;_emit 0x0B;_emit 0x0F;_emit 0x1F;_emit 0x80;_emit 0x00;_emit 0x00;_emit 0x00;_emit 0x00;_emit 0x39;_emit 0xD0;_emit 0x75;_emit 0x34;_emit 0x49;_emit 0x83;_emit 0xC1;_emit 0x02;_emit 0x41;_emit 0x0F;_emit 0xB7;_emit 0x41;_emit 0xFE;_emit 0x44;_emit 0x8D;_emit 0x50;_emit 0xBF;_emit 0x8D;_emit 0x50;_emit 0x20;_emit 0x41;_emit 0x83;_emit 0xFA;_emit 0x19;_emit 0x0F;_emit 0x46;_emit 0xC2;_emit 0x49;_emit 0x83;_emit 0xC0;_emit 0x02;_emit 0x41;_emit 0x0F;_emit 0xB7;_emit 0x50;_emit 0xFE;_emit 0x44;_emit 0x8D;_emit 0x5A;_emit 0xBF;_emit 0x44;_emit 0x8D;_emit 0x52;_emit 0x20;_emit 0x41;_emit 0x83;_emit 0xFB;_emit 0x19;_emit 0x41;_emit 0x0F;_emit 0x46;_emit 0xD2;_emit 0x85;_emit 0xC0;_emit 0x75;_emit 0xC8;_emit 0x39;_emit 0xD0;_emit 0x74;_emit 0x0D;_emit 0x48;_emit 0x8B;_emit 0x1B;_emit 0x48;_emit 0x39;_emit 0xDE;_emit 0x75;_emit 0xAC;_emit 0x31;_emit 0xC0;_emit 0x5B;_emit 0x5E;_emit 0xC3;_emit 0x48;_emit 0x8B;_emit 0x43;_emit 0x30;_emit 0x5B;_emit 0x5E;_emit 0xC3
    };
}
#endif //ifndef _MSC_VER


/////////////////////////////////////////////////////////////////////////////
 
 
//返回函数地址.注意.没有实现序号模式.只能函数名获取
DWORD64 GetProcAddress64(DWORD64 hModule,const char* lpProcName)
{
    return X64Call( (DWORD64)x64proc_GetProcAddress64,2,
                    (DWORD64)hModule,
                    (DWORD64)lpProcName);
}
 
 
//模块名必须带扩展名.不区分大小写.返回句柄
DWORD64 GetModuleHandle64(const wchar_t* lpModuleName)
{
    return X64Call((DWORD64)x64proc_GetModuleHandle64,1,
                    (DWORD64)lpModuleName);
}
 
//取NTDLL64.返回句柄
DWORD64 getNTDLL64()
{
    static DWORD64 hNtdll;
    if(hNtdll == 0)
        hNtdll = GetModuleHandle64(L"ntdll.dll");
    return hNtdll;
}
 
//返回实际读出长度.
size_t ReadMemory64(HANDLE hProcess, DWORD64 lpRead, void* lpBuffer, SIZE_T nSize)
{
    static DWORD64 pfn;
    if (0 == pfn)
        pfn = GetProcAddress64(getNTDLL64(), "NtReadVirtualMemory");
 
    DWORD64 dw64ret = 0;
    X64Call(pfn,5,(DWORD64)hProcess,lpRead,(DWORD64)lpBuffer, (DWORD64)nSize, (DWORD64)&dw64ret);
    return dw64ret;
}
 
//返回实际写出长度.
size_t WriteMemory64(HANDLE hProcess, DWORD64 lpWrite,const void* lpBuffer, size_t nSize)
{
    static DWORD64 pfn;
    if (0 == pfn)
        pfn = GetProcAddress64(getNTDLL64(), "NtWriteVirtualMemory");
    DWORD64 dw64ret = 0;
    X64Call(pfn,5,(DWORD64)hProcess,lpWrite,(DWORD64)lpBuffer, (DWORD64)nSize, (DWORD64)&dw64ret);
    return dw64ret;
}
 
//返回申请到的地址
DWORD64 VirtualAllocEx64(HANDLE hProcess, DWORD64 lpAddress, size_t dwSize, DWORD flAllocationType, DWORD flProtect)
{
    static DWORD64 pfn;
    if (0 == pfn)
        pfn = GetProcAddress64(getNTDLL64(), "NtAllocateVirtualMemory");
 
    DWORD64 tmpAddr = lpAddress;
    DWORD64 tmpSize = dwSize;
    DWORD64 dw64ret = X64Call(pfn, 6,(DWORD64)hProcess,(DWORD64)&tmpAddr,(DWORD64)0, (DWORD64)&tmpSize, (DWORD64)flAllocationType,(DWORD64)flProtect);
    return (dw64ret==NOERROR)?tmpAddr:0;
}
//创建远程线程 返回线程句柄
HANDLE CreateThread64(HANDLE hProcess,DWORD64 lpStartAddress,DWORD64 lpParameter)
{
    static DWORD64 pfn;
    if (pfn == 0)
        pfn = GetProcAddress64(getNTDLL64(), "RtlCreateUserThread");
 
    DWORD64 hThread = 0;
    DWORD64 client_cid[2]={0};
    X64Call(pfn,10,
        (DWORD64)hProcess,        // ProcessHandle
        (DWORD64)NULL,            // SecurityDescriptor
        (DWORD64)FALSE,            // CreateSuspended
        (DWORD64)0,                // StackZeroBits
        (DWORD64)NULL,            // StackReserved
        (DWORD64)NULL,            // StackCommit
        lpStartAddress,            // StartAddress
        lpParameter,            // StartParameter
        (DWORD64)&hThread,        // ThreadHandle
        (DWORD64)&client_cid);    // ClientID
 
    return (HANDLE)(UINT_PTR)hThread;
}
 
 
BOOL VirtualFreeEx64(HANDLE hProcess, DWORD64 lpAddress, size_t dwSize, DWORD dwFreeType)
{
    static DWORD64 pfn = 0;
    if (0 == pfn)
        pfn = GetProcAddress64(getNTDLL64(), "NtFreeVirtualMemory");
 
    DWORD64 tmpAddr = lpAddress;
    DWORD64 tmpSize = dwSize;
    return NOERROR == X64Call(pfn, 4, (DWORD64)hProcess, (DWORD64)&tmpAddr, (DWORD64)&tmpSize, (DWORD64)dwFreeType);
}
 
BOOL VirtualProtectEx64(HANDLE hProcess, DWORD64 lpAddress, size_t dwSize, DWORD NewProtect, DWORD* pOldProtect)
{
    static DWORD64 pfn;
    if (0 == pfn)
        pfn = GetProcAddress64(getNTDLL64(), "NtProtectVirtualMemory");
 
    DWORD64 tmpAddr = lpAddress;
    DWORD64 tmpSize = dwSize;
    return NOERROR == X64Call(pfn, 5, (DWORD64)hProcess, (DWORD64)&tmpAddr, (DWORD64)&tmpSize, (DWORD64)NewProtect, (DWORD64)pOldProtect);
}


2016-12-22 14:05
0
雪    币: 118
活跃值: (27)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
;核心程序的汇编源码
;code by the.night
%define asm_ex1    db 0x48;操作exx变成操作rxx
%define asm_ex2    db 0x4c;操作eax变r8 操作ecx变r9
%define movsxd_rbp_ebp db 0x48,0x63,0xED;清除rbp高位.避免可能存在的bug.
%define mov_edx_high_rax db 0x48,0x89,0xC2,0x48,0xC1,0xEA,0x20;rax拆成edx:eax
 
%macro X64modeEnter 0
    push byte 0x33;        cs寄存器值.x64模式.
    call $+5;        call下一行
    add dword [esp],5;    修改返回地址.跳过本句指令和retf
    retf
%endmacro
%macro X64modeExit 0
    call $+5;        call下一行
    mov dword [esp+4],0x23;    cs寄存器值.WOW模式.
    add dword [esp],0xd
    retf
%endmacro
 
%define pfn        [ebp+8]
%define argCount    [ebp+8+8]
%define arg1        [ebp+8+8+4+8*0]
%define arg2        [ebp+8+8+4+8*1]
%define arg3        [ebp+8+8+4+8*2]
%define arg4         [ebp+8+8+4+8*3]
%define arg5more    [ebp+8+8+4+8*3+8*eax]
 
;DWORD64 X64Call(DWORD64 pfn, int argCount, ...)
    push ebp
    mov ebp,esp
    X64modeEnter
    movsxd_rbp_ebp
;....................X64.................................
;rsp对齐0x10..否则systemcall会报错
    and sp, 0xfff0;
;取参数个数
    mov eax,argCount
    test eax,eax
    je readytocall
;设置参数1
    asm_ex1
    mov ecx,arg1
    sub eax,1
    test eax,eax
    je readytocall
;设置参数2
    asm_ex1
    mov edx,arg2
    sub eax,1
    test eax,eax
    je readytocall
;设置参数3
    asm_ex2
    mov eax,arg3
    sub eax,1
    test eax,eax
    je readytocall
;设置参数4
    asm_ex2
    mov ecx,arg4
    sub eax,1
    test eax,eax
    je readytocall
;设置参数5和以后的参数..判断剩余个数是奇数偶数.如果奇数要esp-8.最后esp才会对齐0x10
    test al,1
    jnz arg5nmore
    sub esp,8
arg5nmore:
    asm_ex1
    push dword arg5more
    sub eax,1
    test eax,eax
    jnz arg5nmore
readytocall:
    sub esp,0x20
    call pfn
;....................X64.................................
    mov_edx_high_rax;
    X64modeExit
    leave
    retn

2016-12-22 14:06
0
雪    币: 12848
活跃值: (9147)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
4
思路不错!然而我选择NtWow64ReadVirtualMemory64
2016-12-22 14:09
0
雪    币: 118
活跃值: (27)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
不能线程和其他复杂API。
记得以前想逆向NtWow64CallXXXX64什么的一个函数怎么调用的。
后来发现这个方法更简单就没研究了。
2016-12-22 14:14
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
不知道为啥 光把X64Call  复制了 但是 直接报错
2020-5-3 00:18
0
雪    币: 23
活跃值: (50)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
请教下楼主,32位跑64位问题不大,包括调试器的崩溃。
但64位进程可以加载32位Dll吗?有思路吗。
2020-5-23 23:52
0
雪    币: 259
活跃值: (283)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
666
2020-5-24 08:05
0
游客
登录 | 注册 方可回帖
返回
//