吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 604|回复: 2
上一主题 下一主题
收起左侧

[会员申请] 申请会员ID:lang1yd【申请通过】

[复制链接]
跳转到指定楼层
楼主
吾爱游客  发表于 2024-9-25 00:05 回帖奖励 |自己
1、申 请 I D:lang1yd
2、个人邮箱:1535517520@qq.com
3、原创技术文章:重做论坛的Synaptics病毒修复工具



一,为什么要重做Synaptics修复工具
很久很久以前,个人电脑和多个U盘上就被 Synaptics病毒 攻占了,使用U盘时经常会传给其它电脑,或被其它电脑上的杀毒软件以病毒之名把U盘上的专用工具给删除了,是直接删除而不是恢复文件,发现中着后,个人以前的做法时, 将Synaptics 病毒的源目录中的exe文件,用个txt代替后修复权限,从而使病毒不能运行.
前些天,又被这个病毒唤醒了,就在网上搜罗. 下载到一个本论坛出品的Synaptics病毒专杀工具,
[PC样本分析] Synaptics蠕虫病毒感染解决方案https://www.52pojie.cn/forum.php ... hlight=%C8%E4%B3%E6
由于权限所限,只能看到第一页.下载了一个1.1.1.1版本的, 也不晓得是不是最新的文件,但是使用过后,正如作者说所:
目前已知问题,对某些exe文件会无法恢复,问题发生的原因不明,程序会自动跳过该类文件但是病毒还在要小心
对长路径名的文件无法处理,这个是Win系统的通病,我也不清楚病毒是怎么做到对长路径和长文件名的感染的
被感染的xlsm文件恢复还处于验证阶段,需要你们的测试结果


同一时间,搜索到一篇文章 ,  偷梁换柱:谨防“Synaptics”蠕虫病毒 https://www.pianshen.com/article/6958951019/
知道了病毒的运作过程.于是用下载的专杀工具,效果感觉很好, U盘空间顿时空了两三百兆出来,  根据工具中扫描时提示的目录信息,我再到U盘的相关目录中去查看,
用exeScope工具来检查某些文件时,发现还是存在感染文件,但是专杀工具识别不了.下面以 病毒样品文件 : Oem7F7.exe (感染文件大小:1.58M,原始文件大小:881K)来测试,
下面是exeScope载入后的结果,确认是感染文件,其中RC数据中DESCRIPTION,EXERESX,EXEVSNX 的内容为 :

DESCRIPTION:
000B139C:53 00 79 00 6E 00 61 00 70 00 74 00 69 00 63 00  S.y.n.a.p.t.i.c.
000B13AC:73 00 20 00 50 00 6F 00 69 00 6E 00 74 00 69 00  s. .P.o.i.n.t.i.
000B13BC:6E 00 67 00 20 00 44 00 65 00 76 00 69 00 63 00  n.g. .D.e.v.i.c.
000B13CC:65 00 20 00 44 00 72 00 69 00 76 00 65 00 72 00  e. .D.r.i.v.e.r.
000B13DC:00 00 00 00                                    ....           


EXERESX:
000B13F0:4D 5A 50 00 02 00 00 00 04 00 0F 00 FF FF 00 00  MZP.............
000B1400:B8 00 00 00 00 00 00 00 40 00 1A 00 00 00 00 00  ?......@.......
000B1410:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000B1420:00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00  ................
000B1430:BA 10 00 0E 1F B4 09 CD 21 B8 01 4C CD 21 90 90  ?...???L?悙
000B1440:54 68 69 73 20 70 72 6F 67 72 61 6D 20 6D 75 73  This program mus
000B1450:74 20 62 65 20 72 75 6E 20 75 6E 64 65 72 20 57  t be run under W
000B1460:69 6E 33 32 0D 0A 24 37 00 00 00 00 00 00 00 00  in32..$7.........
.....
0018D9E0:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
EXEVSNX:   
0018D9F0:31 30 36                                      106            


在 exeScope将资源中的EXERESX内容导出为BIN文件后,直接就是原始文件,  于是准备写一个脚本调用exeScope.exe 来批量导出原始文件, 成是成功了,但是要附带一个exeScope.exe程序在脚本中也不像个事儿.
于是准备根据前辈的分析报告自己来写一个专杀的工具. 顺便用exeinfo PE查看了下载的专杀工具的编译工具是  [Linker 48 ] - MS Visual C# / Basic.NET  ]  - EPToken :0600001E.于是丢到 dnSpy中参考借鉴.经过分析源码,发现扫描不全的原因有:


其一: 专杀工具先取源病毒文件/或感染文件的属性中的描述字段信息作为病毒的特征码,若不能获取到 versionInfo.FileDescription,就不能确定病毒特征码,原代码摘要:
[C#] 纯文本查看 复制代码
string text ="C:\\ProgramData\\Synaptics\\Synaptics.exe";
....
FileVersionInfo versionInfo =FileVersionInfo.GetVersionInfo(text);
CS$<>8__locals1.SynapticsDescription =versionInfo.FileDescription;
....
FileVersionInfo versionInfo2 =FileVersionInfo.GetVersionInfo(openFileDialog.FileName);
CS$<>8__locals1.SynapticsDescription =versionInfo2.FileDescription;
...
if (string.IsNullOrEmpty(CS$<>8__locals1.SynapticsDescription))
{
    MessageBox.Show("获得病毒描述信息失败,退出程序");
    return;
}

用上面的Oem7F7.exe来测试时,会报错: 获得病毒描述信息失败,退出程序 .,然后直接退出. 其二, 判断是否病毒的标准是以文件的描述字段是不是匹配病毒源/或感染文件 的描述字段, 另外 不能取到检测文件的描述信息,也会跳过该文件,原代码摘要:
[C#] 纯文本查看 复制代码
FileVersionInfo versionInfo =FileVersionInfo.GetVersionInfo(text);
    if (versionInfo.FileDescription == null)
    {
        continue;
    }
    if(versionInfo.FileDescription.StartsWith(A_1.SynapticsDescription))
    {
       ....        }
    }

用下面的 C# 来验证专杀工具中的代码检测样品病毒文件描述 的返回值:
[C#] 纯文本查看 复制代码
        private voidbutton7_Click(object sender, EventArgs e)
        {
            stringtext = textBox8.Text;
           FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(text);
            stringdesc = versionInfo.FileDescription;
            if ( descis null)
               Console.WriteLine($"文件:\n{text}\n是否存在:  {File.Exists(text)}\n描述信息为:\n{desc}\n描述为:\nnull");
            else
               Console.WriteLine($"文件:\n{text}\n是否存在:  {File.Exists(text)}\n描述信息为:\n{desc}\n描述信息长度为: {desc.Length}");
        }

返回值 :
文件:F:\下载\Download\病毒\Synaptics病毒\病毒样本\Oem7F7.exe是否存在:  True描述信息为: 描述为:null


结果是取不到描述值, 然后随机试了下其它exe文件, 发现很多文件都取不到描述值,如大家熟悉的程序IDA的卸载程序,exeScope.exe,,也有能取到描述的文件如ida64.exe,下面列举几个验证结果:


文件:D:\ProgramFiles\OllyDbg\IDA\uninstall.exe是否存在:  True描述信息为: 描述信息长度为:0
文件:D:\Program Files\eXeScope\eXeScope.exe是否存在:  True描述信息为: 描述信息长度为:0
文件:D:\Program Files\ollydbg\IDA\ida64.exe是否存在:  True描述信息为:The Interactive Disassembler描述信息长度为:28


所以这会漏检很大一部分文件.  这里测试了几个不同的文件,发现病毒文件取的返回值是null,而不是病毒文件没取到值时,返回不是null,不知这个是不是个例.


其三,文件/文件夹遍历递归时,try语句位置不当, 会使遍历过程中遇到错误后,未遍历的文件会跳过,原代码:
[C#] 纯文本查看 复制代码
internal static void <Main>g__AddDirFiles|4_2(stringdir, ref Program.<>c__DisplayClass4_1 A_1)
{
    try
    {
        DirectoryInfodirectoryInfo = new DirectoryInfo(dir);
        List<FileInfo>list = new List<FileInfo>();
       list.AddRange(directoryInfo.GetFiles("*.exe"));
       list.AddRange(directoryInfo.GetFiles("*.xlsm"));
        foreach (FileInfofileInfo in list)
        {
           A_1.files.Add(fileInfo.FullName);
        }
        DirectoryInfo[]directories = directoryInfo.GetDirectories();
        for (int i = 0; i <directories.Length; i++)
        {
           Program.<Main>g__AddDirFiles|4_2(directories[i].FullName, ref A_1);
        }
    }
    catch (UnauthorizedAccessException)
    {
    }
}

同样以c#测试一个明显的例子:
[C#] 纯文本查看 复制代码
        private voidbutton6_Click(object sender, EventArgs e)
        {
            intlastint = 0;
            try
            {
               for (int i = -7; i < 10; i++)
               {
                   lastint = i;
                   Console.WriteLine(55 / i);
               }
            }
            catch(System.DivideByZeroException)
            {
               Console.WriteLine("发生了除以零的异常,i 的值为: 0");
            }
            catch(Exception ex)
            {
               Console.WriteLine("发生了其他异常: " + ex.Message);
            }
           Console.WriteLine("i 最后的值为: " + lastint);
        }

测试结果:
-7
-9
-11
-13
-18
-27
-55
引发的异常:“System.DivideByZeroException”(位于 Synaptics病毒修复工具.exe 中)发生了除以零的异常,i 的值为: 0
i 最后的值为: 0

用除0测试try,确定抛错后会跳出遍历,后面没有遍历的值会漏掉.所以原程序将try放在foreach外也可能会漏掉一些文件.


因为我看到的帖子时间是2019年12月份发表的,没有权限看后边的页,也不知道作者有没有修复上面的bug,也找不到更好的专杀工具,就参考这个专杀工具重制一个专杀工具.


二.程序设计思路


既然知道有以上三个bug,就先依次打补丁
1. 取病毒特征码   
分析病毒文件:用exeScope检测多个感染文件和病毒原型文件,都有 RCDATA中 DESCRIPTION字段,且 值都为 “S y n a p t ic s  P o i n t i n g   D e v i c e   D r i v er    “
感染文件DESCRIPTION 字段的偏移地址是 0x000B139C-0x000B13DF,  病毒原型DESCRIPTION字段的偏移地址是 0x000B135C - 0x000B139F,
感染的:
000B139C:53 00 79 00 6E 00 6100 70 00 74 00 69 00 63 00 S.y.n.a.p.t.i.c.
000B13AC:73 00 20 00 50 00 6F00 69 00 6E 00 74 00 69 00  s..P.o.i.n.t.i.
000B13BC:6E 00 67 00 20 00 4400 65 00 76 00 69 00 63 00  n.g..D.e.v.i.c.
000B13CC:65 00 20 00 44 00 7200 69 00 76 00 65 00 72 00  e..D.r.i.v.e.r.
000B13DC:0000 00 00                                    ....     


原型:
000B135C:53 00 79 00 6E 00 6100 70 00 74 00 69 00 63 00 S.y.n.a.p.t.i.c.
000B136C:73 00 20 00 50 00 6F00 69 00 6E 00 74 00 69 00  s..P.o.i.n.t.i.
000B137C:6E 00 67 00 20 00 4400 65 00 76 00 69 00 63 00  n.g..D.e.v.i.c.
000B138C:65 00 20 00 44 00 7200 69 00 76 00 65 00 72 00  e..D.r.i.v.e.r.
000B139C: 00 00 00 00                                   ....         
      
可以将里面的二进制数据做为病毒的特征码.
[C#] 纯文本查看 复制代码
        
private static byte[] CreateVirDESCRIPTION()
        {
            //stringvir0 = "S y n a p t i c s   P o i n t i n g   D e v ic e   D r i v e r     ";
            //stringvir1 ="53-00-79-00-6E-00-61-00-70-00-74-00-69-00-63-00-73-00-20-00-50-00-6F-00-69-00-6E-00-74-00-69-00-6E-00-67-00-20-00-44-00-65-00-76-00-69-00-63-00-65-00-20-00-44-00-72-00-69-00-76-00-65-00-72-00-00-00-00-00";
            stringvir2 ="530079006E00610070007400690063007300200050006F0069006E00740069006E0067002000440065007600690063006500200044007200690076006500720000000000";
            
            stringhexString = vir2;
            intbyteCount = vir2.Length / 2;
            byte[]virDESCRIPTION = new byte[byteCount];
            for (inti = 0; i < byteCount; i++)
            {
               virDESCRIPTION[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }
           Console.WriteLine("病毒特征码长度:" + virDESCRIPTION.Length);
           Console.WriteLine(BitConverter.ToString(virDESCRIPTION));
            returnvirDESCRIPTION;
        }

2.病毒文件匹配方式
这里就有两种方式来检测:
A用文件流方式,直接读取 0x000B139C -0x000B13DF 这一段地址来,来与 特征码匹配.
B用win32api读取文件的Rcdata,就是原专杀工具中导出exe的方法.
方式A:
[C#] 纯文本查看 复制代码
        private static byte[]ReadFileBinMark(string filePath)
        {   //检测模式0: BIN   以二进制读取文件的特征值
            intstartAddress = 0x000B139C;
            intendAddress = 0x000B13DF;
            byte[]buffer = ReadFileBin(filePath, startAddress, endAddress);
            returnbuffer;
        }
        private static byte[]ReadFileBin(string filePath, int startAddress, int endAddress)
        {//以二进制读取文件
            intlength = endAddress - startAddress + 1;
            // 创建一个足够大的缓冲区来存储数据
            byte[]buffer = new byte[length];
            // 定位到文件的起始地址并读取数据
            try
            {
               using (FileStream fs = new FileStream(filePath, FileMode.Open,FileAccess.Read,FileShare.ReadWrite))//添加  FileShare.ReadWrite参数来读取已被其它程序打开的文件
               {
                   fs.Position = startAddress;
                   fs.Read(buffer, 0, length);
               }
            }
            catch(IOException ex)
            {
               Console.WriteLine("无法读取文件: " + filePath + "\n\n" +ex.Message);
               MessageBox.Show(ex.Message);
            }
            returnbuffer;
        }



方式B:
[Asm] 纯文本查看 复制代码
private static byte[] ResGetRCDATA(string file, string[]rcLebals,bool limited = false)  //  privateList<byte[]> ResGetRCDATAs(string file, string[] infoNames)
        {   //获取 RCDATA 中 多个字段的二进制 的值 并返回连接到一起的整串,   "#10" 是指 RCDATA,
            if(rcLebals.Length > 0)
            {
               // List<byte[]> rlt = new List<byte[]>(); // 创建 一个元素为byte[]的集合,用于接收结果
               List<byte> rltByte = new List<byte>();               
               IntPtr module = IntPtr.Zero;
               module = WinApi.LoadLibraryEx(file, IntPtr.Zero, flags[0]);  
               string copyFile = "";
               for (int iti = 0;iti <5;iti++)  //尝试5次
               {    
                  Console.WriteLine($"ResGetRCDATA  LoadLibraryEx--flag: {flags[0]}--IntPtr module : {module}");
                   if (module == IntPtr.Zero)
                   {
                       // 加载失败,获取错误代码
                       int errorCode =Marshal.GetLastWin32Error();
                      Console.WriteLine("ResGetRCDATA  LoadLibraryEx --IntPtrmodule -- errorCode :" + errorCode);
                       DialogResult dRlt =MessageBox.Show("文件加载失败 Win32ErrorCode: " + errorCode+ "\n\n" + file+"\n\n是否 尝试其它方式\n\n" +
                           "是----复制源文件并读取镜像文件,文件大小:["+ GetFileSize(file) + "]\n\n" +
                           "否----调用 BIN 方式--待完善\n\n" +
                           "取消--忽略该文件", $"文件加载失败,剩余尝试次数:{5-iti}", MessageBoxButtons.YesNoCancel);                   
                       switch (dRlt)
                       {
                           caseDialogResult.Yes:
                              Random random = new Random();
                              StringBuilder randomStr = new StringBuilder();
                              for(int i = 0; i < 5; i++)
                              {
                                  int randomIndex = random.Next(chars.Length);
                                  randomStr.Append(chars[randomIndex]);
                              }
                              copyFile = file+$".{randomStr}";
                              File.Copy(file, copyFile,true);
                              module = WinApi.LoadLibraryEx(copyFile, IntPtr.Zero,flags[0]); //flags[0] = 0x60
                              if (module == IntPtr.Zero)  //如果还是加载失败,就立即删除复制的文件,不然就在读取完后再删除.
                              {
                                  WinApi.FreeLibrary(module);
                                  File.Delete(copyFile);
                                  Console.WriteLine("文件已被删除: " + copyFile);
                              }                                  
                              break;
                           default:
                              return new byte[] { };                              
                       }
                   }
                   else
                   {
                       break;
                   }
               }

               foreach (string rcLebal in rcLebals)
               {
                   IntPtr resourceInfo =WinApi.FindResourceEx(module, "#10", rcLebal, 0);
                   uint size = WinApi.SizeofResource(module,resourceInfo);
                   IntPtr source =WinApi.LockResource(WinApi.LoadResource(module, resourceInfo));
                   if (size != 0U)
                   {
                       if(limited && size >200) { size = 16; }  //有限制时,且超长时,限制为16字节,针对  "EXERESX" 的摘要信息
                       byte[] array = new byte[size];
                       Marshal.Copy(source, array, 0,array.Length);
                       rltByte.AddRange(array);//  rlt.Add(array);
                   }
               }
               WinApi.FreeLibrary(module);
               if (File.Exists(copyFile))
               {
                   File.Delete(copyFile);//如果存在复制的临时文件,就删除
                   Console.WriteLine("文件已被删除: " + copyFile);
               }
               return rltByte.ToArray();
            }
            returnnew byte[] { };  //  new List<byte[]>()
        }


3.修改 检测文件及文件夹遍历递归方式,将try放在for/foreach 内部
[C#] 纯文本查看 复制代码
private void ScanDirectoryRecursively(string directory, boolisTest, object sender, ref int scanCount, ref int virsCount)
        {
            if(reqStop)
            {
               //(sender as BackgroundWorker).ReportProgress(3);//退出
               Console.WriteLine("ScanDirectoryRecursively--return");
               return;
            }

            foreach(string file in Directory.GetFiles(directory,"*.exe"))  //后续要添加xlsm  ,不要添加  SearchOption.AllDirectories 参数
            {
               try
               {
                   scanCount++;
                   (sender as BackgroundWorker).ReportProgress(1,file + '|' + scanCount);
                   if (!file.ToLower().EndsWith(".exe"))
                       continue;  //过滤以 ".exe_bak" 结尾的文件
                   if (skipCache &&file.Contains("\\._cache_"))
                       continue;  //过滤含"\\._cache_" 的文件
                   //判断文件大小是不是  < 740K                 
                   long.TryParse(GetFileSize(file, false),out longfileSizeB);
                   if (fileSizeB < VIR_FILE_MIN_SIZE)
                       continue;  //过滤小于740K 的文件
                   if (isPause)
                   {  //暂停
                       if(PauseWork(sender)) return;
                   }
                   Console.WriteLine(file);
                   bool isVirus = false; //是否感染
                   if (scanMode == 0)
                   {   //快速匹配
                       if(ReadFileBinMark(file).SequenceEqual(virDESCRIPTION))
                       {
                           isVirus = true;
                       }
                   }
                   else if (ResGetRCDATA(file,resDesLabel).SequenceEqual(virDESCRIPTION))
                   {   //精确匹配
                       isVirus = true;
                   }
                   if (isVirus)
                   {
                       virsCount++;
                       (sender as BackgroundWorker).ReportProgress(2,file + '|' + virsCount);
                       //int tableIndex =0; //用添加的方式时,新项依次追加在后面,要scollView查看最后项,用insert直接插入时,最新的项在最前面
                       // 将病毒信息添加到DataGridView中  // 使用Invoke来在UI线程上执行添加行的操作                         
                       dataGridView1.Invoke(new Action(()=>
                       {
                          //tableIndex=dataGridView1.Rows.Add((dataGridView1.Rows.Count).ToString(),file, Rlt[0]);
                          dataGridView1.Rows.Insert(0, (dataGridView1.Rows.Count).ToString(), file,Rlt[0]);
                       }));
                       // 尝试修复文件
                       string repairResult =RepairFile(file, isTest);

                       // 更新DataGridView中的修复结果  // 使用Invoke来在UI线程上执行更新行的操作
                       dataGridView1.Invoke(new Action(()=>
                       {
                          //dataGridView1.Rows[tableIndex].Cells[2].Value = repairResult;
                          dataGridView1.Rows[0].Cells[2].Value = repairResult;

                       }));
                   }
               }

               catch (UnauthorizedAccessException)
               {
                   Console.WriteLine("file无法访问某些文件夹,因为没有足够的权限。" + file);
                   if (checkBox_showErr.Checked)
                   {
                       MessageBox.Show("file无法访问某些文件夹,因为没有足够的权限。" + file);
                   }
               }
               catch (Exception ex)
               {
                   Console.WriteLine("file发生了其他错误: " + ex.Message + file);
                   if (checkBox_showErr.Checked)
                   {
                       MessageBox.Show("file发生了其他错误: " + ex.Message + file);
                   }
               }
            }
           foreach(string dir in Directory.GetDirectories(directory))//不添加  SearchOption.AllDirectories 参数
            {
               if (reqStop)
               {
                   //(sender as BackgroundWorker).ReportProgress(3);//退出
                  Console.WriteLine("ScanDirectoryRecursively--dir--return");
                   return;
               }

               try
               { // 检查是否是junction文件夹
                   if ((WinApi.GetFileAttributes(dir) & FILE_ATTRIBUTE_REPARSE_POINT)== FILE_ATTRIBUTE_REPARSE_POINT)
                   {
                       Console.WriteLine($"Skippingjunction: {dir}");
                       continue;
                   }
                   ScanDirectoryRecursively(dir, isTest, sender,ref scanCount, ref virsCount);

               }
               catch (UnauthorizedAccessException)
               {
                   Console.WriteLine("dir无法访问某些文件夹,因为没有足够的权限。" + dir);
                   if (checkBox_showErr.Checked)
                   {
                       MessageBox.Show("dir无法访问某些文件夹,因为没有足够的权限。" + dir);
                   }
               }
               catch (Exception ex)
               {
                   Console.WriteLine("dir发生了其他错误: " + ex.Message + dir);
                   if (checkBox_showErr.Checked)
                   {
                       MessageBox.Show("dir发生了其他错误: " + ex.Message + dir);
                   }
               }
            }
        }

4.其它个性功能的定制就不在这里赘述了.只发2个完成的截图,都是原专杀漏检的病毒.
  
5.待完善的:
1)没有感染的xlsm文件, 不能做样本分析, 将病毒 丢到vmware后,也没有得到感染的xlsm病毒文件, xlsm文件的检测还不可用.找到样品了再完善
2)用res方式检测时,若文件已初步写入占用,如被exeScope打开,会检测失败,造成漏检,然后会进行弹窗复制检测处理
3)用BIN方式检测时.会过滤synaptics原型文件, 可用清理环境过能清理病毒原型 "C:\\ProgramData\\Synaptics\\Synaptics.exe"
4)鉴于手中只有两个病毒原型文件,可能其它版本的synaptics病毒会失效.
5)制作匆忙,其它不足之处,请不吝赐教.
6.其它说明:本人不是专业程序员,也不从事软件开发的工作,都是以自学教程为主,博而不专,只是以个人兴趣,有时会写点工具方便自己方便他人.也给几个软件, 研究着写过注册机,.加入论坛目的也是自己兴趣爱好,可以学习到更多的经验教程.

这是个甩不掉的小尾巴: S y n a p t i c s   P o i nt i n g   D e v i c e  D r i v e r   


一,为什么要重做Synaptics修复工具
很久很久以前,个人电脑和多个U盘上就被 Synaptics病毒 攻占了,使用U盘时经常会传给其它电脑,或被其它电脑上的杀毒软件以病毒之名把U盘上的专用工具给删除了,是直接删除而不是恢复文件,发现中着后,个人以前的做法时, 将Synaptics 病毒的源目录中的exe文件,用个txt代替后修复权限,从而使病毒不能运行.
前些天,又被这个病毒唤醒了,就在网上搜罗. 下载到一个本论坛出品的Synaptics病毒专杀工具,
[PC样本分析] Synaptics蠕虫病毒感染解决方案https://www.52pojie.cn/forum.php ... hlight=%C8%E4%B3%E6
由于权限所限,只能看到第一页.下载了一个1.1.1.1版本的, 也不晓得是不是最新的文件,但是使用过后,正如作者说所:
目前已知问题,对某些exe文件会无法恢复,问题发生的原因不明,程序会自动跳过该类文件但是病毒还在要小心
对长路径名的文件无法处理,这个是Win系统的通病,我也不清楚病毒是怎么做到对长路径和长文件名的感染的
被感染的xlsm文件恢复还处于验证阶段,需要你们的测试结果


同一时间,搜索到一篇文章,   偷梁换柱:谨防“Synaptics”蠕虫病毒 https://www.pianshen.com/article/6958951019/
知道了病毒的运作过程.于是用下载的专杀工具,效果感觉很好, U盘空间顿时空了两三百兆出来,  根据工具中扫描时提示的目录信息,我再到U盘的相关目录中去查看,
用exeScope工具来检查某些文件时,发现还是存在感染文件,但是专杀工具识别不了.下面以 病毒样品文件 : Oem7F7.exe(感染文件大小:1.58M,原始文件大小:881K)来测试,
下面是exeScope载入后的结果,确认是感染文件,其中RC数据中DESCRIPTION, EXERESX,EXEVSNX 的内容为 :
DESCRIPTION:
000B139C: 53 0079 00 6E 00 61 00 70 00 74 00 69 00 63 00  S.y.n.a.p.t.i.c.
000B13AC: 73 0020 00 50 00 6F 00 69 00 6E 00 74 00 69 00  s. .P.o.i.n.t.i.
000B13BC: 6E 0067 00 20 00 44 00 65 00 76 00 69 00 63 00  n.g. .D.e.v.i.c.
000B13CC: 65 0020 00 44 00 72 00 69 00 76 00 65 00 72 00  e. .D.r.i.v.e.r.
000B13DC: 00 0000 00                                    ....            


EXERESX:
000B13F0: 4D 5A50 00 02 00 00 00 04 00 0F 00 FF FF 00 00  MZP.............
000B1400: B8 00 0000 00 00 00 00 40 00 1A 00 00 00 00 00  ?......@.......
000B1410: 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000B1420: 00 0000 00 00 00 00 00 00 00 00 00 00 01 00 00  ................
000B1430: BA 1000 0E 1F B4 09 CD 21 B8 01 4C CD 21 90 90  ?...???L?悙
000B1440: 54 6869 73 20 70 72 6F 67 72 61 6D 20 6D 75 73  This program mus
000B1450: 74 2062 65 20 72 75 6E 20 75 6E 64 65 72 20 57  t be run under W
000B1460: 69 6E33 32 0D 0A 24 37 00 00 00 00 00 00 00 00  in32..$7.........
.....
0018D9E0: 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
EXEVSNX:   
0018D9F0: 31 3036                                      106            


在 exeScope将资源中的EXERESX内容导出为BIN文件后,直接就是原始文件,  于是准备写一个脚本调用exeScope.exe来批量导出原始文件, 成是成功了,但是要附带一个exeScope.exe程序在脚本中也不像个事儿.
于是准备根据前辈的分析报告自己来写一个专杀的工具. 顺便用exeinfoPE查看了下载的专杀工具的编译工具是  [ Linker 48 ] - MS Visual C# /Basic.NET  ]  - EPToken : 0600001E.于是丢到 dnSpy中参考借鉴.经过分析源码,发现扫描不全的原因有:


其一: 专杀工具先取源病毒文件/或感染文件的属性中的描述字段信息作为病毒的特征码,若不能获取到 versionInfo.FileDescription,就不能确定病毒特征码,原代码摘要:
[C#] 纯文本查看 复制代码
string text ="C:\\ProgramData\\Synaptics\\Synaptics.exe";
....
FileVersionInfo versionInfo =FileVersionInfo.GetVersionInfo(text);
CS$<>8__locals1.SynapticsDescription =versionInfo.FileDescription;
....
FileVersionInfo versionInfo2 =FileVersionInfo.GetVersionInfo(openFileDialog.FileName);
CS$<>8__locals1.SynapticsDescription =versionInfo2.FileDescription;
...
if(string.IsNullOrEmpty(CS$<>8__locals1.SynapticsDescription))
{
    MessageBox.Show("获得病毒描述信息失败,退出程序");
    return;
}

用上面的Oem7F7.exe来测试时,会报错: 获得病毒描述信息失败,退出程序 .,然后直接退出. 其二, 判断是否病毒的标准是以 文件的描述字段是不是匹配病毒源/或感染文件 的描述字段, 另外 不能取到检测文件的描述信息,也会跳过该文件,原代码摘要:
[C#] 纯文本查看 复制代码
FileVersionInfo versionInfo =FileVersionInfo.GetVersionInfo(text);
    if (versionInfo.FileDescription == null)
    {
        continue;
    }
    if(versionInfo.FileDescription.StartsWith(A_1.SynapticsDescription))
    {
       ....        }
    }

用下面的 C# 来验证专杀工具中的代码 检测样品病毒文件描述 的返回值:
[C#] 纯文本查看 复制代码
        private voidbutton7_Click(object sender, EventArgs e)
        {
            stringtext = textBox8.Text;
           FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(text);
            stringdesc = versionInfo.FileDescription;
            if ( descis null)
               Console.WriteLine($"文件:\n{text}\n是否存在:  {File.Exists(text)}\n描述信息为:\n{desc}\n描述为:\nnull");
            else
               Console.WriteLine($"文件:\n{text}\n是否存在:  {File.Exists(text)}\n描述信息为:\n{desc}\n描述信息长度为: {desc.Length}");
        }

返回值 :
文件:F:\下载\Download\病毒\Synaptics病毒\病毒样本\Oem7F7.exe是否存在:  True描述信息为: 描述为:null


结果是取不到描述值, 然后随机试了下其它exe文件, 发现很多文件都取不到描述值,如大家熟悉的程序IDA的卸载程序,exeScope.exe,,也有能取到描述的文件如ida64.exe,下面列举几个验证结果:


文件:D:\ProgramFiles\ollydbg\IDA\uninstall.exe是否存在:  True描述信息为: 描述信息长度为:0
文件:D:\Program Files\eXeScope\eXeScope.exe是否存在:  True描述信息为: 描述信息长度为:0
文件:D:\Program Files\ollydbg\IDA\ida64.exe是否存在:  True描述信息为:The InteractiveDisassembler描述信息长度为:28


所以这会漏检很大一部分文件.  这里测试了几个不同的文件,发现病毒文件取的返回值是null,而不是病毒文件没取到值时,返回不是null,不知这个是不是个例.


其三,文件/文件夹遍历递归时,try语句位置不当, 会使遍历过程中遇到错误后,未遍历的文件会跳过,原代码:
[C#] 纯文本查看 复制代码
internal static void <Main>g__AddDirFiles|4_2(stringdir, ref Program.<>c__DisplayClass4_1 A_1)
{
    try
    {
        DirectoryInfodirectoryInfo = new DirectoryInfo(dir);
        List<FileInfo>list = new List<FileInfo>();
       list.AddRange(directoryInfo.GetFiles("*.exe"));
       list.AddRange(directoryInfo.GetFiles("*.xlsm"));
        foreach (FileInfofileInfo in list)
        {
           A_1.files.Add(fileInfo.FullName);
        }
        DirectoryInfo[]directories = directoryInfo.GetDirectories();
        for (int i = 0; i <directories.Length; i++)
        {
           Program.<Main>g__AddDirFiles|4_2(directories[i].FullName, ref A_1);
        }
    }
    catch (UnauthorizedAccessException)
    {
    }
}

同样以c#测试一个明显的例子:
[C#] 纯文本查看 复制代码
        private voidbutton6_Click(object sender, EventArgs e)
        {
            intlastint = 0;
            try
            {
               for (int i = -7; i < 10; i++)
               {
                   lastint = i;
                   Console.WriteLine(55 / i);
               }
            }
            catch(System.DivideByZeroException)
            {
               Console.WriteLine("发生了除以零的异常,i 的值为: 0");
            }
            catch(Exception ex)
            {
               Console.WriteLine("发生了其他异常: " + ex.Message);
            }
           Console.WriteLine("i 最后的值为: " + lastint);
        }

测试结果:
-7
-9
-11
-13
-18
-27
-55
引发的异常:“System.DivideByZeroException”(位于 Synaptics病毒修复工具.exe 中)发生了除以零的异常,i 的值为: 0
i 最后的值为: 0

用除0测试try,确定抛错后会跳出遍历,后面没有遍历的值会漏掉.所以原程序将try放在foreach外也可能会漏掉一些文件.


因为我看到的帖子时间是2019年12月份发表的,没有权限看后边的页,也不知道作者有没有修复上面的bug,也找不到更好的专杀工具,就参考这个专杀工具重制一个专杀工具.


二.程序设计思路


既然知道有以上三个bug,就先依次打补丁
1. 取病毒特征码   
分析病毒文件:用exeScope检测多个感染文件和病毒原型文件,都有 RCDATA中 DESCRIPTION字段,且 值都为 “S y n a p t i c s  P o i n t i n g   D e v i ce   D r i v e r    “
感染文件DESCRIPTION 字段的偏移地址是0x000B139C -0x000B13DF,  病毒原型DESCRIPTION字段的偏移地址是 0x000B135C - 0x000B139F,
感染的:
000B139C: 53 0079 00 6E 00 6100 70 00 74 00 69 00 63 00 S.y.n.a.p.t.i.c.
000B13AC: 73 0020 00 50 00 6F00 69 00 6E 00 74 00 69 00  s..P.o.i.n.t.i.
000B13BC: 6E 0067 00 20 00 4400 65 00 76 00 69 00 63 00  n.g..D.e.v.i.c.
000B13CC: 65 0020 00 44 00 7200 69 00 76 00 65 00 72 00  e..D.r.i.v.e.r.
000B13DC:00 00 0000                                    ....     


原型:
000B135C: 53 0079 00 6E 00 6100 70 00 74 00 69 00 63 00 S.y.n.a.p.t.i.c.
000B136C: 73 0020 00 50 00 6F00 69 00 6E 00 74 00 69 00  s..P.o.i.n.t.i.
000B137C: 6E 0067 00 20 00 4400 65 00 76 00 69 00 63 00  n.g..D.e.v.i.c.
000B138C: 65 0020 00 44 00 7200 69 00 76 00 65 00 72 00  e..D.r.i.v.e.r.
000B139C: 00 0000 00                                    ....         
      
可以将里面的二进制数据做为病毒的特征码.
[C#] 纯文本查看 复制代码
        
private static byte[] CreateVirDESCRIPTION()
        {
            //stringvir0 = "S y n a p t i c s   P o i n t i n g   D e v ic e   D r i v e r     ";
            //stringvir1 = "53-00-79-00-6E-00-61-00-70-00-74-00-69-00-63-00-73-00-20-00-50-00-6F-00-69-00-6E-00-74-00-69-00-6E-00-67-00-20-00-44-00-65-00-76-00-69-00-63-00-65-00-20-00-44-00-72-00-69-00-76-00-65-00-72-00-00-00-00-00";
            stringvir2 = "530079006E00610070007400690063007300200050006F0069006E00740069006E0067002000440065007600690063006500200044007200690076006500720000000000";
            
            stringhexString = vir2;
            intbyteCount = vir2.Length / 2;
            byte[]virDESCRIPTION = new byte[byteCount];
            for (inti = 0; i < byteCount; i++)
            {
               virDESCRIPTION[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }
           Console.WriteLine("病毒特征码长度:" + virDESCRIPTION.Length);
           Console.WriteLine(BitConverter.ToString(virDESCRIPTION));
            returnvirDESCRIPTION;
        }

2.病毒文件匹配方式
这里就有两种方式来检测:
A用文件流方式,直接读取 0x000B139C - 0x000B13DF 这一段地址来,来与 特征码匹配.
B用win32api读取文件的Rcdata,就是原专杀工具中导出exe的方法.
方式A:
[C#] 纯文本查看 复制代码
        private static byte[]ReadFileBinMark(string filePath)
        {   //检测模式0: BIN   以二进制读取文件的特征值
            intstartAddress = 0x000B139C;
            intendAddress = 0x000B13DF;
            byte[]buffer = ReadFileBin(filePath, startAddress, endAddress);
            returnbuffer;
        }
        private static byte[]ReadFileBin(string filePath, int startAddress, int endAddress)
        {//以二进制读取文件
            intlength = endAddress - startAddress + 1;
            // 创建一个足够大的缓冲区来存储数据
            byte[]buffer = new byte[length];
            // 定位到文件的起始地址并读取数据
            try
            {
               using (FileStream fs = new FileStream(filePath, FileMode.Open,FileAccess.Read,FileShare.ReadWrite))//添加  FileShare.ReadWrite参数来读取已被其它程序打开的文件
               {
                   fs.Position = startAddress;
                   fs.Read(buffer, 0, length);
               }
            }
            catch(IOException ex)
            {
               Console.WriteLine("无法读取文件: " + filePath + "\n\n" +ex.Message);
               MessageBox.Show(ex.Message);
            }
            returnbuffer;
        }



方式B:
[Asm] 纯文本查看 复制代码
private static byte[] ResGetRCDATA(string file, string[]rcLebals,bool limited = false)  //  privateList<byte[]> ResGetRCDATAs(string file, string[] infoNames)
        {   //获取 RCDATA 中 多个字段的二进制 的值 并返回连接到一起的整串,   "#10" 是指 RCDATA,
            if(rcLebals.Length > 0)
            {
               // List<byte[]> rlt = new List<byte[]>(); // 创建 一个元素为byte[]的集合,用于接收结果
               List<byte> rltByte = new List<byte>();               
               IntPtr module = IntPtr.Zero;
               module = WinApi.LoadLibraryEx(file, IntPtr.Zero, flags[0]);  
               string copyFile = "";
               for (int iti = 0;iti <5;iti++)  //尝试5次
               {    
                  Console.WriteLine($"ResGetRCDATA  LoadLibraryEx--flag: {flags[0]}--IntPtr module : {module}");
                   if (module == IntPtr.Zero)
                   {
                       // 加载失败,获取错误代码
                       int errorCode =Marshal.GetLastWin32Error();
                      Console.WriteLine("ResGetRCDATA  LoadLibraryEx --IntPtrmodule -- errorCode :" + errorCode);
                       DialogResult dRlt =MessageBox.Show("文件加载失败 Win32ErrorCode: " + errorCode+ "\n\n" + file+"\n\n是否 尝试其它方式\n\n" +
                           "是----复制源文件并读取镜像文件,文件大小:["+ GetFileSize(file) + "]\n\n" +
                           "否----调用 BIN 方式--待完善\n\n" +
                           "取消--忽略该文件", $"文件加载失败,剩余尝试次数:{5-iti}", MessageBoxButtons.YesNoCancel);                   
                       switch (dRlt)
                       {
                           caseDialogResult.Yes:
                              Random random = new Random();
                              StringBuilder randomStr = new StringBuilder();
                              for(int i = 0; i < 5; i++)
                              {
                                  int randomIndex = random.Next(chars.Length);
                                  randomStr.Append(chars[randomIndex]);
                              }
                              copyFile = file+$".{randomStr}";
                              File.Copy(file, copyFile,true);
                              module = WinApi.LoadLibraryEx(copyFile, IntPtr.Zero,flags[0]); //flags[0] = 0x60
                              if (module == IntPtr.Zero)  //如果还是加载失败,就立即删除复制的文件,不然就在读取完后再删除.
                              {
                                  WinApi.FreeLibrary(module);
                                  File.Delete(copyFile);
                                  Console.WriteLine("文件已被删除: " + copyFile);
                              }                                  
                              break;
                           default:
                              return new byte[] { };                              
                       }
                   }
                   else
                   {
                       break;
                   }
               }

               foreach (string rcLebal in rcLebals)
               {
                   IntPtr resourceInfo =WinApi.FindResourceEx(module, "#10", rcLebal, 0);
                   uint size = WinApi.SizeofResource(module,resourceInfo);
                   IntPtr source = WinApi.LockResource(WinApi.LoadResource(module,resourceInfo));
                   if (size != 0U)
                   {
                       if(limited && size >200) { size = 16; }  //有限制时,且超长时,限制为16字节,针对  "EXERESX" 的摘要信息
                       byte[] array = new byte[size];
                       Marshal.Copy(source, array, 0,array.Length);
                       rltByte.AddRange(array);//  rlt.Add(array);
                   }
               }
               WinApi.FreeLibrary(module);
               if (File.Exists(copyFile))
               {
                   File.Delete(copyFile);//如果存在复制的临时文件,就删除
                   Console.WriteLine("文件已被删除: " + copyFile);
               }
               return rltByte.ToArray();
            }
            return newbyte[] { };  //  new List<byte[]>()
        }


3.修改 检测文件及文件夹遍历递归方式,将try放在for/foreach 内部
[C#] 纯文本查看 复制代码
private void ScanDirectoryRecursively(string directory, boolisTest, object sender, ref int scanCount, ref int virsCount)
        {
            if(reqStop)
            {
               //(sender as BackgroundWorker).ReportProgress(3);//退出
               Console.WriteLine("ScanDirectoryRecursively--return");
               return;
            }

            foreach(string file in Directory.GetFiles(directory,"*.exe"))  //后续要添加xlsm  ,不要添加  SearchOption.AllDirectories 参数
            {
               try
               {
                   scanCount++;
                   (sender as BackgroundWorker).ReportProgress(1,file + '|' + scanCount);
                   if (!file.ToLower().EndsWith(".exe"))
                       continue;  //过滤以 ".exe_bak" 结尾的文件
                   if (skipCache &&file.Contains("\\._cache_"))
                       continue;  //过滤含"\\._cache_" 的文件
                   //判断文件大小是不是  < 740K                 
                   long.TryParse(GetFileSize(file, false),out longfileSizeB);
                   if (fileSizeB < VIR_FILE_MIN_SIZE)
                       continue;  //过滤小于740K 的文件
                   if (isPause)
                   {  //暂停
                       if(PauseWork(sender)) return;
                   }
                   Console.WriteLine(file);
                   bool isVirus = false; //是否感染
                   if (scanMode == 0)
                   {   //快速匹配
                       if(ReadFileBinMark(file).SequenceEqual(virDESCRIPTION))
                       {
                           isVirus = true;
                       }
                   }
                   else if (ResGetRCDATA(file,resDesLabel).SequenceEqual(virDESCRIPTION))
                   {   //精确匹配
                       isVirus = true;
                   }
                   if (isVirus)
                   {
                       virsCount++;
                       (sender asBackgroundWorker).ReportProgress(2, file + '|' + virsCount);
                       //int tableIndex =0; //用添加的方式时,新项依次追加在后面,要scollView查看最后项,用insert直接插入时,最新的项在最前面
                       // 将病毒信息添加到DataGridView中  // 使用Invoke来在UI线程上执行添加行的操作                         
                       dataGridView1.Invoke(new Action(()=>
                       {
                          //tableIndex=dataGridView1.Rows.Add((dataGridView1.Rows.Count).ToString(),file, Rlt[0]);
                          dataGridView1.Rows.Insert(0, (dataGridView1.Rows.Count).ToString(), file,Rlt[0]);
                       }));
                       // 尝试修复文件
                       string repairResult =RepairFile(file, isTest);

                       // 更新DataGridView中的修复结果  // 使用Invoke来在UI线程上执行更新行的操作
                       dataGridView1.Invoke(new Action(()=>
                       {
                           //dataGridView1.Rows[tableIndex].Cells[2].Value= repairResult;
                          dataGridView1.Rows[0].Cells[2].Value = repairResult;

                       }));
                   }
               }

               catch (UnauthorizedAccessException)
               {
                   Console.WriteLine("file无法访问某些文件夹,因为没有足够的权限。" + file);
                   if (checkBox_showErr.Checked)
                   {
                       MessageBox.Show("file无法访问某些文件夹,因为没有足够的权限。" + file);
                   }
               }
               catch (Exception ex)
               {
                   Console.WriteLine("file发生了其他错误: " + ex.Message + file);
                   if (checkBox_showErr.Checked)
                   {
                       MessageBox.Show("file发生了其他错误: " + ex.Message + file);
                   }
               }
            }
           foreach(string dir in Directory.GetDirectories(directory))//不添加  SearchOption.AllDirectories 参数
            {
               if (reqStop)
               {
                   //(sender asBackgroundWorker).ReportProgress(3);//退出
                  Console.WriteLine("ScanDirectoryRecursively--dir--return");
                   return;
               }

               try
               { // 检查是否是junction文件夹
                   if ((WinApi.GetFileAttributes(dir) &FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT)
                   {
                       Console.WriteLine($"Skippingjunction: {dir}");
                       continue;
                   }
                   ScanDirectoryRecursively(dir, isTest, sender,ref scanCount, ref virsCount);

               }
               catch (UnauthorizedAccessException)
               {
                   Console.WriteLine("dir无法访问某些文件夹,因为没有足够的权限。" + dir);
                   if (checkBox_showErr.Checked)
                   {
                       MessageBox.Show("dir无法访问某些文件夹,因为没有足够的权限。" + dir);
                   }
               }
               catch (Exception ex)
               {
                   Console.WriteLine("dir发生了其他错误: " + ex.Message + dir);
                   if (checkBox_showErr.Checked)
                   {
                       MessageBox.Show("dir发生了其他错误: " + ex.Message + dir);
                   }
               }
            }
        }

4.其它个性功能的定制就不在这里赘述了.只发2个完成的截图,都是原专杀漏检的病毒.

5.待完善的:
1)没有感染的xlsm文件, 不能做样本分析, 将病毒 丢到vmware后,也没有得到感染的xlsm病毒文件, xlsm文件的检测还不可用.找到样品了再完善
2)用res方式检测时,若文件已初步写入占用,如被exeScope打开,会检测失败,造成漏检,然后会进行弹窗复制检测处理
3)用BIN方式检测时.会过滤synaptics原型文件, 可用清理环境过能清理病毒原型 "C:\\ProgramData\\Synaptics\\Synaptics.exe"
4)鉴于手中只有两个病毒原型文件,可能其它版本的synaptics病毒会失效.
5)制作匆忙,其它不足之处,请不吝赐教.
6.其它说明:本人不是专业程序员,也不从事软件开发的工作,都是以自学教程为主,博而不专,只是以个人兴趣,有时会写点工具方便自己方便他人.也给几个软件, 研究着写过注册机,.加入论坛目的也是自己兴趣爱好,可以学习到更多的经验教程.

这是个甩不掉的小尾巴: S y n a p t i c s   P o i nt i n g   D e v i c e  D r i v e r   
提交一直是说有非法字符...无语了.

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
Hmily 发表于 2024-9-25 11:48
I D:lang1yd
邮箱:1535517520@qq.com

申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。

ps:赞一个,这种文章是精品,请登录后把文章整理一下发到病毒分析区,成品可以发到原创区。
3#
lang1yd 发表于 2024-9-25 22:32

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-23 22:03

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表