Nov
2
上一篇谈到:“典型的情况是某些非法内存访问,Glibc会open("/dev/tty",...),write()一些错误信息,然后open("/proc/self/maps", ...)把进程的内存映射表输出。还有一个更常见的情况,那就是用qsort。GCC的qsort实现,会主动open(/proc/meminfo),获取一些信息,通过这些信息来最优化排序时的内存管理。” 通过执行
对于这类情况,ptrace监控进程open系统调用,并获取文件名,检查文件名是否合法,如果合法,予以放行,这样就可以避免上述RE被误判为RF的情况了。
说起来很简单,但是具体做起来就有点麻烦。不过可以从我写woj-land的时候参考的ptrace教程《Playing with ptrace, 玩转ptrace》入手。这篇非常不错,强烈推荐有兴趣的同学学习学习:
Playing with ptrace, Part I — 玩转ptrace(一) http://www.kgdb.info/gdb/playing_with_ptrace_part_i/
Playing with ptrace, Part II — 玩转ptrace(二) http://www.kgdb.info/gdb/playing_with_ptrace_part_ii/
上篇以write系统调用为例,介绍了write系统调用的等价汇编码(当然是早期的了,现在的pc上linux貌似不用0x80了)、截获write系统调用,获取write系统调用的参数和返回值、甚至反转write系统调用的输出。具体的看原文了。
在这里,我需要peek的是read系统调用的参数。以x86为例,一个最简单的read系统调用:
注意:虽然ebx中存放的是地址,但是不是用户程序可以直接读取的,需要通过ptrace的PTRACE_PEEKDATA命令来获取。该命令一次可以获取sizeof(long)个字节的内容,如果要获取字符串的所有内容,就得通过循环来完成。
此外,为了保证代码能够在x86_64架构下通过编译,需要把上述代码做个小修改:
通过这种方式,能够识别出open系统调用打开的文件,在保证系统安全的情况下,改善了Judge的识别能力。
更具体的代码可以参见:
http://code.google.com/p/woj-land/source/browse/trunk/code/judge/judge.h?spec=svn150&r=150#671
strace ./a.out 2>&1 | grep open
可以看到进程执行的open系统调用。对于这类情况,ptrace监控进程open系统调用,并获取文件名,检查文件名是否合法,如果合法,予以放行,这样就可以避免上述RE被误判为RF的情况了。
说起来很简单,但是具体做起来就有点麻烦。不过可以从我写woj-land的时候参考的ptrace教程《Playing with ptrace, 玩转ptrace》入手。这篇非常不错,强烈推荐有兴趣的同学学习学习:
Playing with ptrace, Part I — 玩转ptrace(一) http://www.kgdb.info/gdb/playing_with_ptrace_part_i/
Playing with ptrace, Part II — 玩转ptrace(二) http://www.kgdb.info/gdb/playing_with_ptrace_part_ii/
上篇以write系统调用为例,介绍了write系统调用的等价汇编码(当然是早期的了,现在的pc上linux貌似不用0x80了)、截获write系统调用,获取write系统调用的参数和返回值、甚至反转write系统调用的输出。具体的看原文了。
在这里,我需要peek的是read系统调用的参数。以x86为例,一个最简单的read系统调用:
read("/proc/meminfo", O_RDONLY)
,大致等同于movl $5, %eax ;open的系统调用编号
movl $filename, %ebx ;文件名地址(这里不一定对)
movl $0, %ecx ;open的flags: O_RDONLY
int $0x80
也就是说,可以通过获取x86 CPU寄存器的值来取得系统调用的参数,具体代码如下:movl $filename, %ebx ;文件名地址(这里不一定对)
movl $0, %ecx ;open的flags: O_RDONLY
int $0x80
user_regs_struct regs;
ptrace(PTRACE_GETREGS, child, NULL, ®s);
syscall_id = regs.orig_eax; //因为eax也是用来填写函数返回值的,所以该struct额外增加了一个orig_eax
params[0] = regs.ebx;
params[1] = regs.ecx;
union u{ unsigned long val; char chars[sizeof(long)]; }data;
data.val = ptrace(PTRACE_PEEKDATA, child, params[0], NULL);
ptrace(PTRACE_GETREGS, child, NULL, ®s);
syscall_id = regs.orig_eax; //因为eax也是用来填写函数返回值的,所以该struct额外增加了一个orig_eax
params[0] = regs.ebx;
params[1] = regs.ecx;
union u{ unsigned long val; char chars[sizeof(long)]; }data;
data.val = ptrace(PTRACE_PEEKDATA, child, params[0], NULL);
注意:虽然ebx中存放的是地址,但是不是用户程序可以直接读取的,需要通过ptrace的PTRACE_PEEKDATA命令来获取。该命令一次可以获取sizeof(long)个字节的内容,如果要获取字符串的所有内容,就得通过循环来完成。
此外,为了保证代码能够在x86_64架构下通过编译,需要把上述代码做个小修改:
#if __WORDSIZE == 32
syscall_id = regs.orig_eax;
params[0] = regs.ebx;
params[1] = regs.ecx;
#else
syscall_id = regs.orig_rax;
params[0] = regs.rdi;
params[1] = regs.rsi;
#endif
syscall_id = regs.orig_eax;
params[0] = regs.ebx;
params[1] = regs.ecx;
#else
syscall_id = regs.orig_rax;
params[0] = regs.rdi;
params[1] = regs.rsi;
#endif
通过这种方式,能够识别出open系统调用打开的文件,在保证系统安全的情况下,改善了Judge的识别能力。
更具体的代码可以参见:
http://code.google.com/p/woj-land/source/browse/trunk/code/judge/judge.h?spec=svn150&r=150#671
Nov
1
因为这两个东西占了地方,每次选盘符时总需要往下拉滚动条,很不爽。在网上搜到3篇文章,这里转载记录一下。
http://bbs.pcbeta.com/viewthread.php?tid=729301
http://bbs.pcbeta.com/viewthread.php?tid=729310
http://bbs.pcbeta.com/viewthread.php?tid=733262
“库” @ [HKEY_CLASSES_ROOT\CLSID\{031E4825-7B94-4dc3-B131-E946B44C8DD5}]
“家庭组” @ [HKEY_CLASSES_ROOT\CLSID\{B4FB3F98-C1EA-428d-A78A-D1F5659CBA93}]
修改注册表这里,需要右键->权限,给Administrators “完全控制” 的权限。
如果需要去掉这两项的显示,分别把键值 ShellFolder\Attributes 由原来的 b080010d 改为 b090010d,然后注销(其实Kill掉explorer也行)就行了。如果不想去掉显示,那么修改 SortOrderIndex 键值(默认是0x42、0x43),改到0x52或者更大,就会排到“计算机”后面了。
http://bbs.pcbeta.com/viewthread.php?tid=729301
http://bbs.pcbeta.com/viewthread.php?tid=729310
http://bbs.pcbeta.com/viewthread.php?tid=733262
“库” @ [HKEY_CLASSES_ROOT\CLSID\{031E4825-7B94-4dc3-B131-E946B44C8DD5}]
“家庭组” @ [HKEY_CLASSES_ROOT\CLSID\{B4FB3F98-C1EA-428d-A78A-D1F5659CBA93}]
修改注册表这里,需要右键->权限,给Administrators “完全控制” 的权限。
如果需要去掉这两项的显示,分别把键值 ShellFolder\Attributes 由原来的 b080010d 改为 b090010d,然后注销(其实Kill掉explorer也行)就行了。如果不想去掉显示,那么修改 SortOrderIndex 键值(默认是0x42、0x43),改到0x52或者更大,就会排到“计算机”后面了。
Oct
29
这个词组在ACM/ICPC的各大OJ出现频率还是很高的,意思是使用了“受限制的函数”。
而且几乎没有准确的文档可以定义什么是"Restricted Function"(RF,非彼“RF”)。因为开发者也很郁闷。一个大致可以接受的解释是,任何可能威胁到系统安全的代码都不应该被执行。更严格一点,任何解题所不需要用到的函数都不应该调用。但是这两个解释都不够准确。
作为一个需要编译并运行用户任意代码的系统,必然需要对用户的代码/程序进行额外的处理,过滤可能对服务器产生危险的操作。在woj-land ( http://code.google.com/p/woj-land ) 的实现中,是采用运行时监控程序的执行,通过ptrace来拦截并检查每一个系统调用,如果发现系统调用不在白名单中,即出现RF。具体的代码可参见:http://code.google.com/p/woj-land/source/browse/trunk/code/judge/rf_table.h
白名单机制是最安全的了,但是有缺陷。
首先是很难考虑到所有的情况。举例来说,你用C语言写的A+B来测试的话,需要的系统调用只有几个。大多数情况下能够满足要求,但是有时候却发现不对。比如说SYS_futex这个系统调用,如果不被允许,glibc写的程序在执行时可能会出问题。
其次是过于严格,导致部分常用且不影响系统安全的函数被限制死。比如说fflush,只需要用到SYS_lseek调用即可。
再次是有些异常情况。一个典型的情况是使用 qsort(arr, N, sizeof(arr), cmp); 这样的代码。实际上应当是sizeof(int),不小心写错了,访问出错。典型的情况是某些非法内存访问,Glibc会open("/dev/tty",...),write()一些错误信息,然后open("/proc/self/maps", ...)把进程的内存映射表输出。还有一个更常见的情况,那就是用qsort。GCC的qsort实现,会主动open(/proc/meminfo),获取一些信息,通过这些信息来最优化排序时的内存管理。于是本来应该是运行时错误(段访问异常),即Runtime Error(SIGSEGV)的情况也被误判为Restricted Function了。
終り.
闲谈 Restricted Function #2
而且几乎没有准确的文档可以定义什么是"Restricted Function"(RF,非彼“RF”)。因为开发者也很郁闷。一个大致可以接受的解释是,任何可能威胁到系统安全的代码都不应该被执行。更严格一点,任何解题所不需要用到的函数都不应该调用。但是这两个解释都不够准确。
作为一个需要编译并运行用户任意代码的系统,必然需要对用户的代码/程序进行额外的处理,过滤可能对服务器产生危险的操作。在woj-land ( http://code.google.com/p/woj-land ) 的实现中,是采用运行时监控程序的执行,通过ptrace来拦截并检查每一个系统调用,如果发现系统调用不在白名单中,即出现RF。具体的代码可参见:http://code.google.com/p/woj-land/source/browse/trunk/code/judge/rf_table.h
白名单机制是最安全的了,但是有缺陷。
首先是很难考虑到所有的情况。举例来说,你用C语言写的A+B来测试的话,需要的系统调用只有几个。大多数情况下能够满足要求,但是有时候却发现不对。比如说SYS_futex这个系统调用,如果不被允许,glibc写的程序在执行时可能会出问题。
其次是过于严格,导致部分常用且不影响系统安全的函数被限制死。比如说fflush,只需要用到SYS_lseek调用即可。
再次是有些异常情况。
終り.
闲谈 Restricted Function #2
Oct
26
首先在MATLAB的程序文件中找到如下文件:atlas_Athlon.dll(AMD系列的请用这个,其他的CPU也有相应的问题件),这是对应处理器的数值运算优化文件,然后按如下步骤进行:
1、右击我的电脑,选择属性,在"高级"选项卡中点击"环境变量" ,在系统变量下添加:
变量名:BLAS_VERSION
变量值:C:\Matlab7\bin\win32\atlas_Athlon.dll
如果你安装在D盘,前面就改成D:\Matlab7\bin\win32\atlas_Athlon.dll
2、右击MATLAB7.0的图标,属性,在兼容性 设置里面选择[√]以兼容模式运行这个程序,并选择 Vista Service Pack 2。
再次运行Matlab7 应该就OK了。
1、右击我的电脑,选择属性,在"高级"选项卡中点击"环境变量" ,在系统变量下添加:
变量名:BLAS_VERSION
变量值:C:\Matlab7\bin\win32\atlas_Athlon.dll
如果你安装在D盘,前面就改成D:\Matlab7\bin\win32\atlas_Athlon.dll
2、右击MATLAB7.0的图标,属性,在兼容性 设置里面选择[√]以兼容模式运行这个程序,并选择 Vista Service Pack 2。
再次运行Matlab7 应该就OK了。
Oct
22
一切都是从,那道蚂蚁题,开始的
那题中的蚂蚁有20只,爬在长的木棒一根
左边蚂蚁10只向右爬
右边蚂蚁10只向左爬
蚂蚁爬的速度都相同
一碰头各自原速调头
然后就问,这些个蚂蚁,要碰多少次头才会从木棒上都掉下去
一说起这个问题,可能很多人有看过编程之美4.7 蚂蚁爬杆的问题:有一根27厘米长的细长木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置 处各有一只蚂蚁。木杆很细,不能同时通过2只蚂蚁。开始时候,蚂蚁的头朝左还是朝右是任意的,他们只会朝前走或者掉头,但是不会后退。当任意2只蚂蚁碰头后时,2只蚂蚁会同时掉转头朝反方向走。架设蚂蚁每秒钟可以走一厘米的距离。编写程序,求所有蚂蚁都离开木杆的最短时间和最长时间。
留一些空间不剧透,有兴趣的同学可以先想想然后再往下看。
那题中的蚂蚁有20只,爬在长的木棒一根
左边蚂蚁10只向右爬
右边蚂蚁10只向左爬
蚂蚁爬的速度都相同
一碰头各自原速调头
然后就问,这些个蚂蚁,要碰多少次头才会从木棒上都掉下去
一说起这个问题,可能很多人有看过编程之美4.7 蚂蚁爬杆的问题:有一根27厘米长的细长木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置 处各有一只蚂蚁。木杆很细,不能同时通过2只蚂蚁。开始时候,蚂蚁的头朝左还是朝右是任意的,他们只会朝前走或者掉头,但是不会后退。当任意2只蚂蚁碰头后时,2只蚂蚁会同时掉转头朝反方向走。架设蚂蚁每秒钟可以走一厘米的距离。编写程序,求所有蚂蚁都离开木杆的最短时间和最长时间。
留一些空间不剧透,有兴趣的同学可以先想想然后再往下看。
Oct
16
删除文件夹的时候,windows干的第一件事情貌似是计算所有的文件数量和大小,然后可以在删除过程中告诉你还要多久。有的时候小文件太多,这个过程相当漫长(比如用不了又卸不了的matlab安装文件夹)。这时候用命令提示符 rd /s /q DIRNAME 来删除就不那么罗嗦了。
更进一步,可以修改HK_CLASS_ROOT\Folder\Shell\,增加 一个 DELETE/command, cmd /c rd /s "%1",就可以直接从右键这样删了。
更进一步,可以修改HK_CLASS_ROOT\Folder\Shell\,增加 一个 DELETE/command, cmd /c rd /s "%1",就可以直接从右键这样删了。
Sep
30
PHP:
Array
(
[0] => zu
[1] => ju
)
JS就不用说了,直接用上pinyin.js就好
p.s.
使用的是WinXP的IME生成器(imegen)将全拼的码表(c:\windows\system32\WINPY.MB)解开得到mabiao.txt,然后处理成一个json。
print_r(convert_pinyin("足"));
输出:Array
(
[0] => zu
[1] => ju
)
JS就不用说了,直接用上pinyin.js就好
下载文件 (已下载 7277 次)
p.s.
使用的是WinXP的IME生成器(imegen)将全拼的码表(c:\windows\system32\WINPY.MB)解开得到mabiao.txt,然后处理成一个json。
Sep
30
看了下百度百科对UTF-8的说明,随手写的,基本能用。
比较诡异的是本来UTF8getchar想用strncpy的,但是这个函数有坑....
比较诡异的是本来UTF8getchar想用strncpy的,但是这个函数有坑....
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define alloc(type, size) ((type *)malloc(sizeof(type) * size))
struct UTF8char
{
unsigned short length;
char data[7];
};
unsigned UTF8getcharlen(const char *s)
{
unsigned char t = (unsigned char) s[0];
if (t < 0x80) //0xxx xxxx
return 1;
else if (t < 0xe0) //110x xxxx
return 2;
else if (t < 0xf0) //1110 xxxx
return 3;
else if (t < 0xf8) //1111 0xxx
return 4;
else if (t < 0xfc) //1111 10xx
return 5;
else if (t < 0xfe) //1111 110x
return 6;
else //0xff
return 1;
}
int UTF8getchar(UTF8char *c, const char *s)
{
int i;
c->length = UTF8getcharlen(s);
for (i = 0; i < c->length && s[i] != 0; i++)
c->data[i] = s[i];
c->data[i] = 0;
return (i == c->length);
}
int UTF8cmp(const UTF8char *c, const char *s)
{
return strncmp(c->data, s, c->length);
}
int main()
{
char linebuf[4096];
UTF8char c;
scanf("%s", linebuf);
int reti = UTF8getchar(&c, linebuf);
assert(reti != 0);
printf("%d %s\n", c.length, c.data);
return 0;
}
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define alloc(type, size) ((type *)malloc(sizeof(type) * size))
struct UTF8char
{
unsigned short length;
char data[7];
};
unsigned UTF8getcharlen(const char *s)
{
unsigned char t = (unsigned char) s[0];
if (t < 0x80) //0xxx xxxx
return 1;
else if (t < 0xe0) //110x xxxx
return 2;
else if (t < 0xf0) //1110 xxxx
return 3;
else if (t < 0xf8) //1111 0xxx
return 4;
else if (t < 0xfc) //1111 10xx
return 5;
else if (t < 0xfe) //1111 110x
return 6;
else //0xff
return 1;
}
int UTF8getchar(UTF8char *c, const char *s)
{
int i;
c->length = UTF8getcharlen(s);
for (i = 0; i < c->length && s[i] != 0; i++)
c->data[i] = s[i];
c->data[i] = 0;
return (i == c->length);
}
int UTF8cmp(const UTF8char *c, const char *s)
{
return strncmp(c->data, s, c->length);
}
int main()
{
char linebuf[4096];
UTF8char c;
scanf("%s", linebuf);
int reti = UTF8getchar(&c, linebuf);
assert(reti != 0);
printf("%d %s\n", c.length, c.data);
return 0;
}