MSSQL认证过程中error-msg编码问题

0x00 前言

在MSSQL认证过程中,不同版本的TDS协议error-msg编码不同。如何用正确的姿势处理这些乱码,化腐朽为神奇是本篇要做的。

0x01 UTF-8编码与UTF-16编码

UTF-8UTF-16都处理相同的Unicode字符,并且都是可变长度编码,每个字符最多需要32位。但是,在选择多语言数据库或列中使用UTF-8还是UTF-16方面存在重要的差异:

UTF-8使用8位编码常见的ASCII字符,包括英语和数字。在UTF-8中,ASCII字符占一个字节,拉丁,希腊和西里尔字母的其他字符占两个字节,中文和日语字符占三个字节

但是UTF-16在编号0到65535(在UCS-2和UTF-16中都可用)中的每个字符至少使用2个字节,而编号65536到1114111使用与UTF-8相同的4个字节

存储边界如下表所示:

Code Range (hexadecimal)Code Range (decimal)Storage bytes with UTF-8Storage bytes with UTF-16
000000 – 00007F (ASCII)0 - 12712
000080 – 00009F
0000A0 – 0003FF
000400 – 0007FF
128 – 159
160 – 1,023
1,024 – 2,047
22
000800 – 003FFF
004000 – 00FFFF
2,048 - 16,383
16,384 – 65,535
32
010000 – 03FFFF
040000 – 10FFFF
65,536 – 262,143
262,144 – 1,114,111
44

0x02 TDS编码需求

TDS协议版本编码格式
TDS 4ASCII
TDS 5ASCII
TDS 7.xUTF16LE

0x03 python解码

TDS 7.0抓包

在这里插入图片描述

源码

err_msg = '\x28\x75\x37\x62\x20\x00\x27\x00\x73\x00\x61\x00\x27\x00\x20\x00\x7b\x76\x55\x5f\x31\x59\x25\x8d\x02\x30'
print err_msg.decode('utf16')
# out:用户 'sa' 登录失败。

Tips

  1. TDS4的报错是ascii码的,所以直接在python中print就可以了
  2. 后来发现TDS7的报错信息都是两个字节一个单元,ascii码的字符已变成了两个字节,并且跟着\x00,以为是UTF8,后来发现UTF8是单字节的,效率比UTF16高。

0x04 参考文献

https://www.freetds.org/tds.html
https://malwaremusings.com/scripts/parsetds-py-2/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于msg的文章目处理Error Msg的方法小结不针对任何人的说: 看到有人把Error Msg写死到代码里,我就有上去忽他一巴掌的冲动。比如如下代码: int funcFoo() { UpdateData(); int error_code = 0; if (!IsInPutsUseName()) error_code = -1; else if(!IsInputAllPsw()) error_code = -2; else if(!IsTwoPswTheSame()) error_code = -3; else if(!IsThePswMachWithDatabase()) error_code = -4; if (error_code != 0) { switch(error_code) { case -1 : MessageBox("请输入用户名,然后重试!", "未输入用户名", MB_OK | MB_ICONWARNING); break; case -2 : MessageBox("请输入所有的密码,然后重试!", "未输入密码", MB_OK | MB_ICONWARNING); break; case -3 : MessageBox("您输入的两次密码不一致,请重新输入!", "密码不一致", MB_OK | MB_ICONWARNING); break; case -4 : MessageBox("您输入的密码错误,请重新输入", "密码错误", MB_OK | MB_ICONWARNING); break; case default : break; } DeleteInputPsw(); return error_code; } UpdateData(false); return error_code; } 理由如下: 1. 这样的源码不易阅读。假设用户提供的一个错误信息,我要追踪其源码,我去那里找呀?可能有很多处地方都会有重复的类似的MSG出现,比如"请输入用户名,然后重试!"和"请您输入用户名,然后重试!"就会被认为是2条不同的MSG。这样很难排错。 2. 用户那里有可能弹出你估计之外的错误。实际上我们经常遇到这种情况,某程序崩溃探出一个错误号,没信息。因为没有对应好。 3. 不利于发展为多语言版本?(你指望专业翻译在你的代码里搜索字符串?) 4.不利于全局统计。估计自己都不知道自己的工程里已经存在了多少种MSG字符串了吧? 5.专业软件的错误信息是应该由专业语言措辞人员去对应的,而不是由程序员决定最终的版本。比如我代码里写一个errorcode:992,“没输密码!”,就会被专业措辞人员修饰为"请输入用户名,然后重试!" 解决的方法 也有多种,各有其优点和不足之处,写在这里供大家参考: 1.最古老的做法,是把信息写入一个文本文件里面: // xxxxxxxxxx 一些注释 xxxxxxxxxxx // xxxxxxxxxx 一些注释 xxxxxxxxxxx // xxxxx Error Code : 998 // xxxxx Msg : "请输入用户名,然后重试!" // xxxxx 描述: ... #define Error_998_MSG "请输入用户名,然后重试!" // xxxxxxxxxx 一些注释 xxxxxxxxxxx // xxxxxxxxxx 一些注释 xxxxxxxxxxx // xxxxx Error Code : 999 // xxxxx Msg : "xxxxxxxxx, xxxxxxxxxxxxxxx!" // xxxxx 描述: ... #define Error_999_MSG "xxxxxxxxxxxxxxxx!" 诸如此类的做法,当系统启动的时候把这些资源读入内存 优点:已经基本上解决了上述所说的弊病; 缺点:跨平台交互不容易,尤其是文件内码不同的情况,比如utf-8环境、ansi char环境、unicode环境........... 2. 写入xml文件里面:(推荐) 这种做法和上述方法类似,不过解决了上述方法的缺点。常用于Web相关的开发。 优点:标记语言,交互方便。扩展方便,功能强大且无限制。 缺点:编写人员必须熟悉xml语法,或者有专用的用于简化生成这个xml文件的程序。 3. 写入数据库里面: 应用这种方法的也很多,我就遇到若干这种做法的项目。形象一点的说,你可以参考Sql Server的错误信息,它也是写在一个系统表里面。 优点:利用SQL的优势,编写、修改都很方便,程序员、翻译、维护人员和用户都很轻松。客户甚至可以自己修改MSG信息。 缺点:一般这种做法只用于数据库相关的应用,比如MIS系统。另外,如果出现数据库根本连接不上的错误,这种错误信息还要当作特例解决。 另外,交互-速度较慢。 今天在论坛上偶见此问题,遂废话一堆,抛砖引玉,希望大家批评指正。 -------------

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值