近日闲的蛋疼发现一款某地外挂被火绒爆勒索,本来准备安排一哈它的勒索功能
结果发现sys直接明文存放在exe里,我也懒得花钱,遂dump之
IDA看了下发现是Safengine Shielden v2.4.0.0
直接加载sys后发现往afd.sys挂了一个注册表回调,回调入口是跳板
由于驱动直接加载会返回C0000001导致立刻被卸载,无法直接dump
于是改用模拟器加载并在真实DriverEntry处dump整个sys内存:
经过调试发现Safengine保护的驱动会使用DriverObject->DriverSection进行PsLoadedModuleList的遍历并修复导入表
如果在模拟器中给上假的
DriverSection会导致SE访问到非法内存
于是我们给模拟器补上自己伪造的
PsLoadedModuleList和
DriverSection
:
DriverObject.DriverSection = (PVOID)m_DriverLdrEntry;
补完后可以正常执行到真实入口点,可以看到这个sys执行的第一次API是RtlInitUnicodeString
我们定义代码从加壳sys的.sedata/.vmp节执行到.text 或INIT 就算进入真实入口点
bool bIsUnknownSection = (0 == memcmp((char *)SectionHeader[i].Name, ".text\0\0\0", 8)
|| 0 == memcmp((char *)SectionHeader[i].Name, "INIT\0\0\0\0", 8)) ? false : true;
bool bIsUnknownSection = (0 == memcmp((char *)SectionHeader[i].Name, ".text\0\0\0", 8)
|| 0 == memcmp((char *)SectionHeader[i].Name, "INIT\0\0\0\0", 8)) ? false : true;
if(currentModule == ctx->m_ImageBase && ctx->m_IsPacked && !ctx->m_ImageRealEntry)
{
FakeSection_t *section = NULL;
if (ctx->FindSectionByAddress(address, §ion) && !section->IsUnknownSection)
{
ctx->m_ImageRealEntry = address;
}
}
if(currentModule == ctx->m_ImageBase && ctx->m_IsPacked && !ctx->m_ImageRealEntry)
{
FakeSection_t *section = NULL;
if (ctx->FindSectionByAddress(address, §ion) && !section->IsUnknownSection)
{
ctx->m_ImageRealEntry = address;
}
}
至此,我们可以完整dump出刚刚进入真实入口点时的加壳驱动
virtual_buffer_t imagebuf(ctx.m_ImageEnd - ctx.m_ImageBase);
uc_mem_read(uc, ctx.m_ImageBase, imagebuf.GetBuffer(), ctx.m_ImageEnd - ctx.m_ImageBase);
FILE *fp = fopen("dump.sys", "wb");
fwrite(imagebuf.GetBuffer(), ctx.m_ImageEnd - ctx.m_ImageBase, 1, fp);
fclose(fp);
virtual_buffer_t imagebuf(ctx.m_ImageEnd - ctx.m_ImageBase);
uc_mem_read(uc, ctx.m_ImageBase, imagebuf.GetBuffer(), ctx.m_ImageEnd - ctx.m_ImageBase);
FILE *fp = fopen("dump.sys", "wb");
fwrite(imagebuf.GetBuffer(), ctx.m_ImageEnd - ctx.m_ImageBase, 1, fp);
fclose(fp);
对比加壳sys和dumpsys可以发现 safengine使用了代码自修改
从区段自带可写入属性就可以看出这一点
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2019-2-7 11:24
被hzqst编辑
,原因: