avatar

目录
调试C Sharp中Async异步

调试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)

定位到样本入口点,代码:

Code
1
2
3
4
5
6
public static void Main()
{
App app = new App();
app.InitializeComponent();
app.Run();
}

三行代码,分别为初始化一个APP对象,初始化APP组件,运行APP,先看InitializeComponent()里是怎么运行的。

Code
1
2
3
4
5
6
7
8
9
public class App : Application
{
// Token: 0x06000015 RID: 21 RVA: 0x000025A2 File Offset: 0x000007A2
[DebuggerNonUserCode]
[GeneratedCode("PresentationBuildTasks", "4.0.0.0")]
public void InitializeComponent()
{
base.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
}

其中base.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);在WPF程序中,用来指定应用程序XAML路径,应用程序将根据这个文件来创建窗口界面。

在资源中可以找到“MainWindow.baml”,其实这个就是前面加载的“MainWindow.xaml”。

可以看见第一行的x:Class="Winservices.MainWindow",直接在MainWindow类下断,断到恶意代码内容。

MainWindow代码如下:

Code
1
2
3
4
5
6
7
8
9
10
public MainWindow()
{
this.InitializeComponent();
string result = MainWindow.DropingExe().GetAwaiter().GetResult();
bool flag = result != "ab";
if (flag)
{
MainWindow.Running(MainWindow.GetttingValidPath());
}
}

第三行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都和下面的代码基本一样:

Code
1
2
3
4
5
6
7
8
public static Task<string> DropingExe()
{
MainWindow.<DropingExe>d__10 <DropingExe>d__ = new MainWindow.<DropingExe>d__10();
<DropingExe>d__.<>t__builder = AsyncTaskMethodBuilder<string>.Create();
<DropingExe>d__.<>1__state = -1;
<DropingExe>d__.<>t__builder.Start<MainWindow.<DropingExe>d__10>(ref <DropingExe>d__);
return <DropingExe>d__.<>t__builder.Task;
}

举个例子,代码来自Stackify

C#代码:

Code
1
2
3
4
5
6
7
[HttpGet, Route("api/HttpClient/GetGWB")]
public async Task<bool> GetGWB()
{
HttpClient hc = new HttpClient();
await hc.GetAsync("http://geekswithblogs.net/Default.aspx");
return true;
}

Dnspy的代码:

Code
1
2
3
4
5
6
7
8
9
10
11
[DebuggerStepThrough, AsyncStateMachine(typeof(HttpClientController.<GetGWB>d__3)), HttpGet, Route("api/HttpClient/GetGWB")]
public Task<bool> GetGWB()
{
HttpClientController.<GetGWB>d__3 <GetGWB>d__ = new HttpClientController.<GetGWB>d__3();
<GetGWB>d__.<>4__this = this;
<GetGWB>d__.<>t__builder = AsyncTaskMethodBuilder<bool>.Create();
<GetGWB>d__.<>1__state = -1;
AsyncTaskMethodBuilder<bool> <>t__builder = <GetGWB>d__.<>t__builder;
<>t__builder.Start<HttpClientController.<GetGWB>d__3>(ref <GetGWB>d__);
return <GetGWB>d__.<>t__builder.Task;
}

代码的功能为异步发送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/

https://stackoverflow.com/questions/65110369/dnspy-showing-strange-disassembly-code-for-async-methods

文章作者: Yenn_
文章链接: https://0xdf1001f.github.io/2021/10/20/%E8%B0%83%E8%AF%95C-Async%E5%BC%82%E6%AD%A5/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Wei's Blog

评论