调试C Sharp中Async异步
以前也调过很多C#里有Async异步操作的恶意软件,不过没仔细看过什么情况,写个笔记。
基本信息
样本是赛门铁克最近曝光的针对南亚的攻击活动,疑似针对阿富汗,AsyncRAT,不过这个背景在样本调试中并不是很重要。
470cd1645d1da5566eef36c6e0b2a8ed510383657c4030180eb0083358813cd3
调试
Costura打包
样本是一个C#程序,刚拉进Dnspy的时候,查看资源列表发现很多以Costura.开头的资源文件,并且还有一个类名为“XXX_processedByFody”,可以发现样本是由Costura打包出来的,Fody是.NET开发的一个扩展工具,Costura是其中一个插件,Costura可以将依赖作为资源文件打包进.exe文件中。从图中来看,样本中打包的内容似乎是创建计划任务所需的文件。
如何提取这个通过Fody.Costura打包的内容,找到了一个工具https://github.com/dr4k0nia/Simple-Costura-Decompressor,不过似乎是需要从Dnspy中先将资源保存出来再使用。
Windows Presentation Foundation(WPF)
定位到样本入口点,代码:
1 | public static void Main() |
三行代码,分别为初始化一个APP对象,初始化APP组件,运行APP,先看InitializeComponent()里是怎么运行的。
1 | public class App : Application |
其中base.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
在WPF程序中,用来指定应用程序XAML路径,应用程序将根据这个文件来创建窗口界面。
在资源中可以找到“MainWindow.baml”,其实这个就是前面加载的“MainWindow.xaml”。
可以看见第一行的x:Class="Winservices.MainWindow"
,直接在MainWindow类下断,断到恶意代码内容。
MainWindow代码如下:
1 | public MainWindow() |
第三行this.InitializeComponent();
一样的初始化,第四行的string result = MainWindow.DropingExe().GetAwaiter().GetResult();
用了异步操作与C2地址通信,并且Wait操作完成。
Async
异步代码类似多线程操作,但是也不全是多线程。单线程也可以使用异步代码,同一线程同时并发多个任务,多线程也可以使用异步分别运行多个并发任务。
就像在家烧开水,在等待水烧开的过程中可以玩会手机、看会电视,烧水这个任务并不影响玩手机。异步可以同时进行多个任务。例如在Http请求中,Http请求常会需要很长时间才能处理,使用异步可以在等待服务器响应的过程中执行其他内容。
在异步代码中,和平时逆向的代码不太一样,第一次看见MainWindow.DropingExe().GetAwaiter().GetResult()
这一行,我以为是调用DropingExe()
(此时我害很天真以为这里面就是很直观的恶意代码),然后等待方法调用完成,完成后获取返回结果,接着运行下一行代码。
实际上,编译器会将代码转换成Async State Machine,并且State Machine在后台完成大量复杂工作,使开发人员可以编写简单的代码,开发简单了,逆向就不一定了。
MainWindow.DropingExe()
代码如下,这是初始化State Machine的代码,所以异步代码的初始化State Machine都和下面的代码基本一样:
1 | public static Task<string> DropingExe() |
举个例子,代码来自Stackify
C#代码:
1 | [HttpGet, Route("api/HttpClient/GetGWB")] |
Dnspy的代码:
1 | [DebuggerStepThrough, AsyncStateMachine(typeof(HttpClientController.<GetGWB>d__3)), HttpGet, Route("api/HttpClient/GetGWB")] |
代码的功能为异步发送Http请求到一个指定url,但是在使用Dnspy逆向过程中,可以发现只剩下的初始化State Machine的代码,除了初始化代码,连State Machine的代码都看不见。
后来Stack Overflow一位老哥说:“这里显示的代码只是一部分,只显示了初始化State Machine的代码,代码生成非常复杂,在调试器中Options->Decompiler->C#->Show hidden decompiler generated classes and methods
可以看见State Machine代码”。
设置了之后出现了MainWindow.<DropingExe>d__10
这个类,类下有MoveNext()
、SetStateMachine()
方法,再继续调试,可以在IAsyncStateMachine.MoveNext()
断下,继续调试恶意代码。
链接
https://stackify.com/csharp-async-await-task-performance/
https://www.codeproject.com/Articles/535635/Async-Await-and-the-Generated-StateMachine
https://devblogs.microsoft.com/premier-developer/dissecting-the-async-methods-in-c/
https://weblogs.asp.net/dixin/understanding-c-sharp-async-await-1-compilation
https://ranjeet.dev/understanding-how-async-state-machine-works/