破译SQLServer for Linux预览版的3.5GB内存限制 (RHEL篇)
微软发布了SQLServer for Linux,但是安装竟然需要3.5GB内存,这让大部分云主机用户都没办法尝试这个新东西
这篇我将讲解如何破解这个内存限制
要看关键的可以直接跳到第6步,只需要替换4个字节就可以破解这个限制
首先按照微软的给出的步骤安装和配置
https://docs.microsoft.com/zh-cn/sql/linux/sql-server-linux-setup-red-hat-
到执行/opt/mssql/bin/sqlservr-setup时可以看到这个错误
sqlservr: This program requires a machine with at least 3250 megabytes of memory.
-
按错误文本查找消息在哪个文件里面
[root@localhost ~]# cd /opt/mssql/bin/ [root@localhost bin]# grep -irn "3250" [root@localhost bin]# grep -irn "megabytes of memory" Binary file sqlpackage matches Binary file sqlpackage matches Binary file sqlservr matches [root@localhost bin]# strings sqlservr | grep "megabytes of memory" %s: This program requires a machine with at least %zu megabytes of memory. [root@localhost bin]# strings sqlpackage | grep "megabytes of memory" %s: This program requires a machine with at least %zu megabytes of memory.
看来sqlservr和sqlpackage会检测这个限制,并且这个限制是一个常量
-
查找错误消息的位置
[root@localhost bin]# hexdump -C sqlservr | less
找到这里
0006baf0 72 69 6e 67 29 00 25 73 3a 20 54 68 69 73 20 70 |ring).%s: This p| 0006bb00 72 6f 67 72 61 6d 20 72 65 71 75 69 72 65 73 20 |rogram requires |
可以看到消息在0006baf6的位置
-
查找调用错误消息的位置
[root@localhost bin]# objdump -C -S sqlservr | less
找到这里
23940: 48 8d 35 af 81 04 00 lea 0x481af(%rip),%rsi # 6baf6 23947: 31 c0 xor %eax,%eax 23949: 48 89 ca mov %rcx,%rdx 2394c: 48 89 d9 mov %rbx,%rcx 2394f: e8 6c e4 fe ff callq 11dc0 <fprintf@plt> 23954: bf 01 00 00 00 mov $0x1,%edi 23959: e8 e2 e1 fe ff callq 11b40 <exit@plt>
判断的函数在这里
238e0: 55 push %rbp 238e1: 48 89 e5 mov %rsp,%rbp 238e4: 53 push %rbx 238e5: 48 83 ec 78 sub $0x78,%rsp // 把这个函数接收的第二个参数放到rbx // 参考 https://en.wikipedia.org/wiki/X86_calling_conventions (System V AMD64 ABI) 238e9: 48 89 f3 mov %rsi,%rbx // 调用sysinfo获取内存大小 // rdi是第一个参数,是一个在堆栈中的struct sysinfo // 参考 https://linux.die.net/man/2/sysinfo 238ec: 48 8d 7d 88 lea -0x78(%rbp),%rdi 238f0: e8 3b e3 fe ff callq 11c30 <sysinfo@plt> // 偏移量的计算如下 // -0x78: uptime (struct sysinfo的开头地址) // -0x70: loads[3] // -0x58: totalram // -0x50: freeram // -0x48: sharedram // -0x40: bufferram // -0x38: totalswap // -0x30: freeswap // -0x28: procs (short为什么占8个字节?看https://en.wikipedia.org/wiki/Data_structure_alignment) // -0x20: totalhigh // -0x18: freehigh // -0x10: mem_unit (同样,int 4个字节 align 4个字节) // 计算出rax = totalram * mem_unit 238f5: 8b 45 f0 mov -0x10(%rbp),%eax 238f8: 48 0f af 45 a8 imul -0x58(%rbp),%rax // 如果rax小于rbx则跳到23909,即显示内存不足并退出 238fd: 48 39 d8 cmp %rbx,%rax 23900: 72 07 jb 23909 23902: 48 83 c4 78 add $0x78,%rsp 23906: 5b pop %rbx 23907: 5d pop %rbp 23908: c3 retq
调用判断的函数的代码在这里
// 这里的第二个参数是3250000000,可以看到内存的限制值是一个常量 // 0xc1b71080 = 3250000000 1486a: be 80 10 b7 c1 mov $0xc1b71080,%esi 1486f: 4c 89 e7 mov %r12,%rdi 14872: e8 69 f0 00 00 callq 238e0
顺道再用hexdump查找一下有多少处地方用了80 10 b7 c1,结果是只有一处
00014860 00 00 48 89 df e8 66 15 00 00 be 80 10 b7 c1 4c |..H...f........L| 00014870 89 e7 e8 69 f0 00 00 0f 57 c0 0f 29 85 70 ff ff |...i....W..).p..|
-
使用python修改代码
改条件判断的jb或者改8010b7c1都可以,我这里把8010b7c1改成更小的值0080841e(512M)[root@localhost bin]# mv sqlservr sqlservr.old [root@localhost bin]# python >>> a = open("sqlservr.old", "rb").read() >>> b = a.replace("\x80\x10\xb7\xc1", "\x00\x80\x84\x1e") >>> open("sqlservr", "wb").write(b) [root@localhost bin]# chmod +x sqlservr
可以继续替换掉sqlpackage中的限制值,但是不替换也可以使用
-
继续配置sqlserver
[root@localhost bin]# /opt/mssql/bin/sqlservr-setup [root@localhost bin]# systemctl status mssql-server
如果你执行完命令后没有看到服务正常启动,可能是之前的配置没有成功导致的
删除mssql的数据文件夹并重试即可[root@localhost bin]# rm -rf /var/opt/mssql [root@localhost bin]# /opt/mssql/bin/sqlservr-setup
正常启动后可以看到
● mssql-server.service - Microsoft(R) SQL Server(R) Database Engine
Loaded: loaded (/usr/lib/systemd/system/mssql-server.service; enabled; vendor preset: disabled)
Active: active (running) since Mon 2016-12-05 22:50:06 EST; 20s ago
Main PID: 2625 (sqlservr)
CGroup: /system.slice/mssql-server.service
├─2625 /opt/mssql/bin/sqlservr
└─2638 /opt/mssql/bin/sqlservr
Dec 05 22:50:10 localhost.localdomain sqlservr[2625]: 2016-12-06 03:50:10.85 spid17s Server is listening on [ 0.0.0.0 ...433].
Dec 05 22:50:10 localhost.localdomain sqlservr[2625]: 2016-12-06 03:50:10.87 Server Server is listening on [ 127.0.0....434].
Dec 05 22:50:10 localhost.localdomain sqlservr[2625]: 2016-12-06 03:50:10.89 Server Dedicated admin connection suppor...1434.
Dec 05 22:50:10 localhost.localdomain sqlservr[2625]: 2016-12-06 03:50:10.89 spid17s SQL Server is now ready for clien...ired.
Dec 05 22:50:11 localhost.localdomain sqlservr[2625]: 2016-12-06 03:50:11.77 spid6s Starting up database 'tempdb'.
Dec 05 22:50:12 localhost.localdomain sqlservr[2625]: 2016-12-06 03:50:12.02 spid6s The tempdb database has 1 data file(s).
Dec 05 22:50:12 localhost.localdomain sqlservr[2625]: 2016-12-06 03:50:12.02 spid20s The Service Broker endpoint is in...tate.
Dec 05 22:50:12 localhost.localdomain sqlservr[2625]: 2016-12-06 03:50:12.03 spid20s The Database Mirroring endpoint i...tate.
Dec 05 22:50:12 localhost.localdomain sqlservr[2625]: 2016-12-06 03:50:12.09 spid20s Service Broker manager has started.
Dec 05 22:50:12 localhost.localdomain sqlservr[2625]: 2016-12-06 03:50:12.14 spid5s Recovery is complete. This is an ...ired.
Hint: Some lines were ellipsized, use -l to show in full.
启动成功后使用微软提供的命令行工具连接也可以,使用windows上的客户端连接也可以
https://docs.microsoft.com/zh-cn/sql/linux/sql-server-linux-setup-tools
下图是2G内存上运行的mssql
Ubuntu上的破解会不一样,因为Ubuntu安装前会运行检测程序,如何破解将在下一篇讲解
题外话
- mssql for linux有日期限制和联网验证,预计正式版以后免费的可能性很小
- mssql在linux上编译开启了pie选项并且没有符号表导出,这让gdb跟踪变得很困难,但这次破解只需要静态分析
- mssql的本体封在了/opt/mssql/lib/sqlservr.sfp里面,如果需要破解其他限制可能还需要花功夫研究这个文件
- 7楼DJLNET
- 农夫大神就是叼 O(∩_∩)O哈哈~
- 6楼源河
- 强!
- 5楼JRoger
- 农夫要亮
- 4楼mspeer
- 膜拜
- 3楼桦仔
- After a few more SFP files are opened for certificates and NetFX4, and then we end up at sqlservr.sfp. And inside here, it loads things familiar to deep dive SQL Server pros…first we see the program binary load sqlservr.exe, SqlDK.dll, sqllang.dll, SQLOS.dll, and sqlmin.dll. I omitted some output for readability.,,open(“/opt/mssql/lib/sqlservr.sfp”, O_RDONLY) = 7,…omitted,pread(7, “sqlservr.exe\0”, 13, 13398) = 13,…omitted,pread(7, “SqlDK.dll\0”, 10, 14079) = 10,…omitted,pread(7, “sqllang.dll\0″, 12, 14382) = 12,…omitted,pread(7, “SQLOS.dll\0”, 10, 14418) = 10,…omitted,pread(7, “sqlmin.dll\0”, 11, 14511) = 11
- 2楼jinzhenshui
- 牛X
- 1楼troy.cui
- 微软那么吃内存,有点瞎搞