在自己新加的节中 用c++写的比较简单的方法实现了简单的调用winapi函数messagebox()

上回是实现了简单的取反加密  这次是在此基础上 实现的

思路大致如下

为了调用api函数 我在网上搜到好多资料  基本上全部都是汇编的
而汇编我很陌生 所以好多看不懂是什么意思 不过有文章解释 大概是这样的思路

Win32PE 程序 其PE头中有一个导入函数表 对应的代码段中 所用到的api函数在动态链接库中的地址
而Win32PE 病毒只有一个代码段 并不存在导入函数段 因此无法像pe程序那样直接调用相关的api函数地址

而应该首先找到这些api函数在相应动态链接库中的地址 基本步骤

调用loadlibraryA()函数来载入指定的动态链接库,并将它映射到当前进程使用的地址空间。一旦载入,即可访问库内保存的资源
调用getprocaddress()函数获得api函数对应的入口地址 (这两个函数都在kernel32.dll的导出表中)

所以需要先得找到kernel32.dll的基地址(一般有三种 这里只说一种兼容性好的)
因为本程序未使用这方面的知识 若要了解 看这篇文章即可 网址:

http://hi.baidu.com/xx375/blog/item/ddcaeed836fc6070d0164e78.html

言归正传

本程序是直接获得的winapi函数messageboxA 的地址
由于windows的dll文件 映射到内存后(loadlibraryA) 其中的api地址是固定的
(不太怎么确定 为了保险起见   每次手动获取一下)
这个地址获得的很不好 好多时候必须得先获得地址后 再copy过来 (待解决)

程序如下
#include <iostream.h>
#include <windows.h>
int main(int argc, char* argv[])
{
HINSTANCE h;
char dllname[] ="User32";
h = GetModuleHandle(dllname);
if(h == NULL)
{h = LoadLibrary(dllname);}

DWORD p=(DWORD)GetProcAddress(h,"MessageBoxA");

cout<<"Addr of MessageBoxA:  "<<hex<<p<<endl;  //0x76acea71(本机器)  0x77d507ea(其它机器)

此时已经获得了messagebox的函数地址 接下来是
定义相应的函数指针  用得到的MessageBoxA的地址去 初始化这个函数指针 (就可以传参调用)

typedef  int (WINAPI * PMESSAGEBOX)(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT UType);

PMESSAGEBOX pmessagebox = (PMESSAGEBOX)p ;
pmessagebox(NULL,NULL,NULL,NULL) ;
return 0 ;
}

然后就是如何让被感染的pe文件去执行messagebox函数
所以要将   (获取地址的这些代码) 和 (调用messagebox函数的代码)一同复制到新加节中即可
在上次取反的基础上 代码如下:
注意一点 messagebox的参数 不可以使用字符串去初始化 因为字符串是放在全局变量区中的
这里有一个重定位的问题 关于这个问题 我还没解决 在此先掠过(下篇文章就是变量的重定位)
怎么弄才可以不用字符串去初始化变量(强哥出谋划策 NXX FOR ME)
大概意思是 将要显示在messagebox上的字符转换成一个byte数组 去初始化messagebox的参数
先将字符串psz 转换成 PBYTE类型的(不变也行 为了美观) 即下边转换成的ha[]数组
然后将其输出 得到字符串所对应的16进制的表示 将其copy出来  这就是messagebox的参数

#include <stdio.h>
#include <windows.h>
char * psz = "哈哈!!" ;
void main()
{PBYTE pb = (PBYTE)psz;
int len = strlen(pb); //strlen 不含\0 的实际大小字节数

for (int i=0; i<=len; i++)
{
printf("0x%x,",pb[i]);
//输出结果为  BYTE ha[] = {0xb9,0xfe,0xb9,0xfe,0x21,0x21,0x0};
//这就是我们想要的结果 也就是 字符串    “哈哈!!”
}}
可以将输出一下ha[]看看 printf("%s\n",ha); //哈哈!!

好了 messagebox的地址找到了 messagebox的参数也解决了
接下来就是 将这些内容copy到新加节的代码中
程序如下
abc 是三个数组 分别为相应的字符串   "加壳成功!!  OK!! 哈哈!!"
0x76acea71  为本次程序获得的 messagebox的地址
而PMESSAGEBOX  是用来接受messagebox函数一样参数 一样返回值的 函数指针

typedef  int (WINAPI * PMESSAGEBOX)(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT UType);

定义变量 并用地址初始化它 调用即可 pmessagebox(NULL,sz,title,NULL);
其中的参数是 调用之前 做好的

void  _stdcall QF(PVOID address,DWORD len)
{
DWORD i=0;

BYTE a[] = {0xbc,0xd3,0xbf,0xc7,0xb3,0xc9,0xb9,0xa6,0x21,0x21,0x0};//加壳成功!!
       BYTE b[] = {0x4f,0x4b,0x0,0x0,0x0};//OK!!
BYTE c[] = {0xb9,0xfe,0xb9,0xfe,0x21,0x21,0x0};//哈哈!!

char* sz = (char*)c ;
char* title = (char*)b;

       PBYTE buf=(PBYTE)address;

for ( i=0; i<len; i++)
{
   buf[i]=~buf[i];
}

DWORD messagebox =  0x76acea71 ;

PMESSAGEBOX pmessagebox = (PMESSAGEBOX)messagebox ;

pmessagebox(NULL,sz,title,NULL);
}

到此即可 上回取反加密中 此函数的首末地址是 运行之前先调试看一下 获得的;
这次 把这个问题解决了   即现在可以 动态的获得函数的首末地址(别的程序也可以)
获取函数真实地址的函数

在调试的时候 在Watch中 输入某个函数的名字 则会看到其真实地址
而在程序中采取这种方式 将其赋值给一个DWORD类型的变量
则其真实地址RealAdd 会变为 另外一个数 JmpAdd 下边分析一下原因

写一个add()的小函数
并在main中调用一下add(1,1)

在函数定义的位置反汇编得到

5:    int Add (int a , int b)
6:    {
00401030 55                   push        ebp
00401031 8B EC                mov         ebp,esp
00401033 83 EC 40             sub         esp,40h

在调用函数的地方反汇编得到

16:       Add(1,1);
004010A8 6A 01                push        1
004010AA 6A 01                push        1
004010AC E8 54 FF FF FF       call        @ILT+0(Add) (00401005)
004010B1 83 C4 08             add         esp,8

此时应该可以看到 函数的真正地址为 00401030  而后边调用的时候 call的是 00401005 地址处
这是为什么呢 而之前我说的在程序中将函数地址赋值给一个DWORD类型后 数值会发生变化 即00401030  变成了 00401005

而跟到00401005 地址处 发现是这样的

@ILT+0 (?Add@@YAHHH@Z):
00401005 E9 26 00 00 00       jmp         Add (00401030)

在这里发现了函数的真正地址   这就有点明白了
应该是编译器的工作完成的 当调用函数的时候 会先call某一个地址 在这个地址处 再jmp到函数的真实地址处
为什么这样做 (不太清楚 可能是为了安全吧)

所以要获得函数的真正地址需要到那个假的地址处 去解析jmp指令的操作码
因为jmp指令是E9 占一个字节  即跳过这个字节即可得到真正地址
所以将函数地址先转换成 PBYTE 类型的 自加1即可到所要的偏移地址
jmp option  指令是 跳到相对于下一条指令地址偏移option的地址处

下一条指令地址: 这样求  Function 函数的假地址 加上 jmp option 这条指令的长度(5)
再加上偏移    : 即 解析jmp的操作码  先(PBYTE)Function++; 此时是指向jmp后边的偏移地址
                再将其转换为 (DWORD*)类型 取出里边的内容 即为要求偏移地址

函数代码如下:

DWORD GetRealFuncaddress(PVOID Function)
{
PBYTE add= (PBYTE)Function;
add++;
DWORD* Piyi = (DWORD*) add;
DWORD RealAdd=  (DWORD)Function +  5  +  *Piyi;
return RealAdd;
}

这个函数就可以获得某个函数的首地址
本程序是要获得 我们要往新加节中copy内容的 那个函数的首末地址
为了获得末地址 我在紧跟这个函数后写一个空函数 去获得它的首地址 作为咱函数的末地址即可

总结:
获得messagebox的地址 不是正而不经的办法 主要因为自己汇编得力不好 不过必须实现那种方法
正是因为汇编不好 jmp指令的 含义也没搞明白
还有就是 变量的重定位 问题
继续努力 各个攻破