经典病毒:熊猫烧香函数全分析(一)

Posted on 2022-04-21  18 Views


全过程在虚拟机环境下运行
为了锻炼自己的汇编分析能力,本文将不会参考ida生成的伪代码
因为已经知道这是个病毒,所以不需要按照病毒分析流程先去网站上查了。
使用exeinfo pe查看病毒样本
在这里插入图片描述然后可以发现,此程序是使用Delphi编写的,需要注意的是Delphi使用Register调用约定,参数从左向用优先使用寄存器(eax,edx,ecx)传参。
接下来使用ida打开目标样本
在这里插入图片描述
首先观察第一个代码块,开头部分很多是Delphi自动生成的,我们不关心,从第一个call下面的push ebp开始才是我们关心的内容,点进下面的几个地址看了一下在这里插入图片描述
有一些ida没有识别出来的汉字字符串,手动处理一下
在这里插入图片描述出现了一些意义不明,和一些看起来像是作者感言的字符串
在这里插入图片描述
继续分析,dword_40E7D4这个地址发现是一个未初始化的变量,并且作为了参数和一串字符串一起传给了下面的函数sub_403C98,紧接着又将unk_40E7D8和一个字符串作为参数再次传递给这个函数调用,并且可以发现这两个未初始化变量的地址很近,只相差4个字节,猜测存储的是一个地址。
跟进这个函数看看
在这里插入图片描述
发现里面又有两个未知函数调用,点进去稍微看了一下不是很好分析,于是改先用动态看一下他都干了啥
在这里插入图片描述F7跟进看一下
在这里插入图片描述此时到了第一个未知函数调用,传入的参数ax是20,F8步过一下,观察发现返回的eax,ecx是两个地址在这里插入图片描述
数据框跟进一下看看存的是啥
在这里插入图片描述
发现一个存的是1,一个是0,暂时还不知道是干啥的,继续往下看
在这里插入图片描述

在第二个函数调用时传入的三个参数分别是字符串,20,和一个地址,刚刚看到内个地址存储的值为0。继续F8步过看看这个函数干了啥
在这里插入图片描述发现刚刚为0的49000C现在存储了一串字符,所以合理猜测这两个函数的功能分别是初始化一段空间和将字符串复制到指定地址,继续F7步进发现结束了调用,重新回到了主函数。在这里插入图片描述
所以可以得到这个函数sub_403C98的功能就是复制字符串到指定地址,在ida中更改函数名便于后续分析在这里插入图片描述
接下来又是一个函数调用,传入的参数分别是两个字符串并在cx存储了一个未知变量,继续动态调试跟进看看传入的是啥
在这里插入图片描述发现cx存储的是个地址0018FF74,跟进看了一眼,这个地址是栈空间,目前指向的值为零
进入函数,找到关键循环,开始分析
在这里插入图片描述很显然,这里是一个解密函数,key为
wboy
待解密字符串为
"++戊+缓"叛*聋+肛+删"蚊*苜+兆++*
翻译成c++代码的话,大概长这个样子

#include<iostream>
#include<string>
using namespace std;
int main(){
    string key = "xboy";
    string str = "\"++戊+缓\"叛*聋+肛+删\"蚊*苜+兆++*";
    int len_key = key.length();
    int len_str = str.length();
    for(int i = 1; i <= len_str; i ++){
        int j = key[i%len_key] % 10;
        char res = j ^ str[i-1];
        cout << res;
    }
} 

运行后得到结果
在这里插入图片描述到这里这个函数的功能就差不多明白了,回到上一个函数,改名,继续分析
在这里插入图片描述

这里解密完,下一步正常来讲应该就是验证了,刚好,下一个函数执行完后有一个跳转是直接结束程序运行,那可以直接确定这个sub_40CBBC就是验证函数了,改名为CheckCode后继续分析,下面又是一个decode和一个解密函数,替换对应的key和str之后得到下面的结果,显然这里也属于程序启动校验部分
在这里插入图片描述继续向下分析,发现连续三个没有参数的函数调用,并且在这三个函数之后是一个消息循环,可以判定这三个函数就是病毒程序的主要实现部分,依次分析
在这里插入图片描述首先进入第一个函数,shub_408024开始分析
在这里插入图片描述
这个长度...有点令人望而生畏,不慌,一点一点来
在这里插入图片描述第一个部分是一些初始化工作,没什么好分析的,继续往下看,下面是一个小循环,每次开辟8个字节的栈空间,重复84h次
在这里插入图片描述
再继续看下一个部分这个部分主要由4个未知函数组成,一个个开始分析

在这里插入图片描述首先是第一个函数sub_40277C,点进去发现很明显的WindowsAPI函数,所以可以很轻松的得到这个函数的功能是获取程序所在路径(包含程序名)。

在这里插入图片描述
更改函数名称为getPathName,继续分析下一个函数sub_405684
在这里插入图片描述
发现这个函数主要是一个循环,作用是从程序所在路径的最后一个字符开始向前遍历,直到遇到字符“\”,“/”或“:”,可以得到这个函数的功能便是将程序路径去掉程序名称,将函数名称改为getPath后继续分析
在这里插入图片描述我们可以看到下一个函数sub403ED4使用了两个参数,一个是不包含程序名的文件路径,一个是字符串"Desktop.ini"显然这个是程序名,这个函数的功能已经呼之欲出了,动态分析一下看看结果在这里插入图片描述这个函数执行完之后得到了一个字符串,这个字符串正是文件路径和“Desktop.ini”拼接得到的,那么很显然,这个函数的功能是拼接字符串,将函数改名为strcat,继续向下分析。
下一个函数是sub4057A4,进入之后发现功能只是调用一个函数,继续点进去分析,看到了很多WindowsAPi函数,很明显的显示出了这个函数的功能是搜索文件,并将其从文件时间转换至Dos时间,传入的字符串是Desktop.ini这个文件,所以这个函数的功能便是找到这个文件,并将最后修改时间改为dos时间。如果没有找到文件则设置FatDate = -1,即返回ax = -1,再经sub_4057A4 进行ax+1操作,即若未找到文件则返回ax=0
在这里插入图片描述

这个函数功能的分析差不多就结束了,改函数名,继续向下分析
在这里插入图片描述这部分的代码是在文件存在时的情况下执行的,逻辑也很简单,可以分析出来这个部分会将Desktop_.ini文件删除

下一个块是Desktop_.ini文件不存在时执行的部分

在这里插入图片描述这部分将程序读进内存中,并设置了一个标志位,在之后检查文件尾的数据是否为0.如果为0则说明被感染过,可以继续执行
在这里插入图片描述继续向下分析,在通过检查后获取文件路径并存入var_3D8,然后将其作为参数和var_3D4一起传入sub_40532,下面开始分析这个函数。
在这里插入图片描述根据明显的WindowsAPI函数可以判断出这个函数的功能是将路径字符串中的小写字母全部转为大写,然后存入edi的地址,也就是var_3D4,这个函数功能分析结束,更改函数名为ToUpper,然后继续向下分析在这里插入图片描述
下一个要分析的函数为sub_4054BC,进入函数,结构很简单,主体便是调用api函数GetSystemDirectoryA获取系统路径,然后稍作处理返回
在这里插入图片描述

所以这个函数的功能就是获取系统路径,将这个函数重命名为GetSysPath,继续向下分析函数sub_403F8C,进入之后发现ida的分析存在报错,所以先试用动态调试看一下
在这里插入图片描述
发现在栈中获得了一个字符串,这个字符串是由先前压入栈中的字符串“drivers\”和“spoclsv.exe”拼接到获取的系统路径上得到的,所以我们暂且认定这个函数的功能是将多个字符串拼接到一个字符串上,将其更名为CatStrsToStr,然后此时这个块内不再有未知函数了。可以很轻松的看出块代码功能是比对病毒是否已经在系统目录下伪装成spcolsv.exe,如果是则跳转。

在这里插入图片描述我们先来分析不跳转的,也就是病毒程序不在系统目录也没有伪装的情况。
在这里插入图片描述这段代码也很长,依次分析,首先第一个call,sub_4060D4
点进去之后发现这段函数的实现也很长,还是慢慢分析

其中第一个需要注意的函数是sub_4005028,在这个函数中的主要调用函数调用了大量的winAPI,通过这些api函数可以分析出来他的作用是从动态链接库kernel32.dll中导出函数

在这里插入图片描述重命名sub_4005028函数为ExportFunFromKernel,继续向下分析

在这里插入图片描述
下面直接跳转进入loc_4061D0,这里检测了一下al的值是否小于1,也就是检测了一下函数是否成功导入,如果成功导入则跳转loc_4061D0

在这里插入图片描述接下来继续向下分析函数sub_406028,这里有个小循环,使指针指向了字符串中字符“\”的下一个地址
在这里插入图片描述小循环下面只有一个比较关键的函数sub_4012C

在这里插入图片描述

接下来点进去分析,这个函数跳转有点多,不太好分析,写个伪代码草稿
在这里插入图片描述

int main()//这只是个辅助分析的草稿
{
    //a = edx  '\'所在位置+1 
    //b = ecx
    //str = var_4 eax
    //len = ebx = strlen(eax)
    int dx,cx;
    string str,*arg;
    if(str != 0)
    {
        if(len != 0)
        {
            dx --;
            if(dx != 0 && dx <= len)
            {
                len = len - dx;
                if(cx > ebx)
                {
                    cx = len;
                    arg = &str[a];
                }
                else
                {
                    arg = &str[a];
                }
            }
            else if(a == 0)
            {
                cx = len;
                arg = &str[0];
            }
        }
    } 
}

嗯,这样可读性就比光看汇编高多了,可以分析出来这个函数的功能是将字符串切片,准确的说是将eax指向的字符串从edx部分开始切片,也就是仅保留‘\’后的部分。

更名为CatEaxFromEdxAndRetLenToEcx
在这里插入图片描述
到这里函数sub_406028也就分析完了,总结一下他的功能就是只保留字符串最后一个“\”后面的字符,也就是当前调用的程序名。
继续向下分析,下一个函数是sub_405FA8

在这里插入图片描述
结构比较简单,直接静态分析

在这里插入图片描述
这里有个小循环,一般都是主要功能实现的地方,重点关注这里,首先这里要分析的函数是sub_402804,点进去看看。

在这里插入图片描述
功能很简单,如果字符是小写字母则将其转换为大写,更改函数名为CharUpper

在这里插入图片描述

继续分析这个循环,下一个函数是sub_404124,这个函数有一个截取后缀名的动作,动态分析了一下没有明显作用,暂且跳过,然后返回调用函数sub_405FA8继续分析,后续只是做了一些还原现场的操作,可以认为这个函数分析完了,返回上一级调用函数继续分析在这里插入图片描述这里传入了三个变量,一个104h,一个var_140,一个[ebx+24h],其中有两个变量不知道存的是什么,动态分析看一下
在这里插入图片描述var_140指向了一段没有值的栈地址,edx存储的是字符串“[System Prosess]”

开始分析这个函数

在这里插入图片描述

未完待续,最近要准备比赛,先小鸽一阵


欢迎来到parafish的个人博客,这里是一个正在努力的ctfer

路虽远,行则必至