分类 C编程 下的文章

在读ptrunnel的代码时,发现一个很好的用法记录一下,可用于密码的输入框,不回显输入内容,可用于很多场景。
代码如下:

static int terminal_echo_off(int fd)
{
struct termios term;
if (isatty(fd) == 0)
{
#ifdef DEBUG
printf("the file %i is not a terminaln", fd);
#endif /* DEBUG */
return -1;
}
if (tcgetattr(fd, &term) < 0)
{
#ifdef DEBUG
perror("tcgetattr: ");
#endif /* DEBUG */
return -1;
}
term.c_lflag &= ~ECHO;
if (tcsetattr(fd, TCSANOW, &term) < 0)
{
#ifdef DEBUG
perror("tcsetattr: ");
#endif /* DEBUG */
return -1;
}
return 0;
}
static int terminal_echo_on(int fd)
{
struct termios term;
if (isatty(fd) == 0)
{
#ifdef DEBUG
printf("the file %i is not a terminaln", fd);
#endif /* DEBUG */
return -1;
}
if (tcgetattr(fd, &term) < 0)
{
#ifdef DEBUG
perror("tcgetattr: ");
#endif /* DEBUG */
return -1;
}
term.c_lflag |= ECHO;
if (tcsetattr(fd, TCSANOW, &term) < 0)
{
#ifdef DEBUG
perror("tcsetattr: ");
#endif /* DEBUG */
return -1;
}
return 0;
}

在Unix操作系统的动态链接库的世界中,LD_PRELOAD就是这样一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。
大家想到着就邪恶了吧,今天看proxychanis代码发现的,和win平台sockscap32类似。
看代码test.c

#include 
#include 
#include 
int main(void)
{
    char *passwd="abcd";
    char in_buff[10];
    printf("-->input your passwd:");
    scanf("%s", in_buff);
    if( strcmp(passwd,in_buff) != 0) {
        printf("passwd errn");
        exit(-1);
    }
    printf("ok!. open doorn");
}

库代码hack.c

#include 
int strcmp(const char *s1, const char *s2)
{
    printf("hack function invoked. s1=[%s],s2=[%s]n", s1, s2);
    return 0;
}
[root@localhost preload]# gcc -o test test.c
[root@localhost preload]# ./test
-->input your passwd:123
passwd err
[root@localhost preload]# gcc -shared -o hack.o hack.c
[root@localhost preload]# ls -l hack.so
-rwxr-xr-x 1 root root 4116 Apr 13 15:52 hack.so
[root@localhost preload]# LD_PRELOAD="./hack.so"
[root@localhost preload]# ./test
-->input your passwd:123
passwd err
[root@localhost preload]# export LD_PRELOAD="./hack.so"
[root@localhost preload]# ./test
-->input your passwd:123
hack function invoked. s1=[abcd],s2=[123]
ok!. open door
[root@localhost preload]#

这是一种思路,还有一种最直接的办法用ltrace
ltrace是跟踪调用库函数的工具

[root@localhost preload]# export LD_PRELOAD=
[root@localhost preload]# ltrace ./test
(0x69951c, 0x699ab0, 0, 0, 0x699e58)                                              = 0x6998e4
__libc_start_main(0x80484a4, 1, 0xbf948364, 0x8048530, 0x8048520 
printf("-->input your passwd:")                                                   = 21
__isoc99_scanf(0x80485ff, 0xbf9482a2, 0x9acce0, 0x9abff4, 0x8048530-->input your passwd:123
)              = 1
strcmp("abcd", "123")                                                             = 1
puts("passwd err"passwd err
)                                                                = 11
exit(1 
+++ exited (status 1) +++
[root@localhost preload]#

用C写了一个扫描类的监控程序,为了监控的实时性,所有要发送邮件。
前提机器中必须有sendmail程序,sendmail的目录自己定义。
我测试环境的信息

[root@localhost sendmail]# uname -a
Linux localhost.localdomain 2.6.32-358.el6.i686 #1 SMP Thu Feb 21 21:50:49 UTC 2013 i686 i686 i386 GNU/Linux
[root@localhost sendmail]# cat /etc/issue
CentOS release 6.4 (Final)
Kernel r on an m

代码如下,很简单只要是思路。

#include 
#include 
#include 
//借助sendmail命令发送邮件
//邮件格式如下:
/*
*From: John Doe 
*Sender: Michael Jones 
*To: Mary Smith 
*Subject: Saying Hello
*Date: Fri, 21 Nov 1997 09:55:06 -0600
*Message-ID: <1234@local.machine.example>
*
*This is a message just to say hello.
*So, "Hello".
*/
int main(void)
{
        FILE    *fp;
        char    buffer[512];
        if( (fp=popen("/usr/sbin/sendmail -t","w")) == NULL)
        {
                perror("open /usr/sbin/sendmail errorn");
                printf("%sn", strerror(errno));
        }
        fputs("From: John Doe n", fp);
        fputs("Sender: Michael Jones n", fp);
        fputs("To: key1088 n", fp);
        fputs("Subject: Hello,wordn", fp);
        fputs("Date: Fri, 21 Nov 1997 09:55:06 -0600n", fp);
        fputs("Message-ID: <1234@local.machine.example>n", fp);
        fputs("n", fp);
        fputs("This is a message just to say hello.n", fp);
        fputs("So, Hellon", fp);
        if( pclose(fp) != 0) {
                printf("send mail error.n");
                exit(1);
        }
        printf("send mail done.n");
}
[root@localhost sendmail]# cc sendmail.c
[root@localhost sendmail]# a.out
send mail done.
[root@localhost sendmail]# tail /var/log/maillog
Mar 16 15:43:45 localhost postfix/sendmail[2124]: fatal: Recipient addresses must be specified on the command line or via the -t option
Mar 16 15:47:33 localhost postfix/qmgr[1059]: 2B7F53F87B: from=, size=431, nrcpt=1 (queue active)
Mar 16 15:47:33 localhost postfix/qmgr[1059]: 667E83F89F: from=, size=431, nrcpt=1 (queue active)
Mar 16 15:47:33 localhost postfix/smtp[2130]: 2B7F53F87B: to=, relay=none, delay=1075, delays=1075/0.08/0/0, dsn=4.4.3, status=deferred (Host or domain name not found. Name service error for name=163.com type=MX: Host not found, try again)

因为测试环境没有联网,所以是发送不成功。

sscanf() - 从一个字符串中读进与指定格式相符的数据.
函数原型:
int sscanf( string str, string fmt, mixed var1, mixed var2 ... );
int scanf( const char *format [,argument]... );
说明:
sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。
其中的format可以是一个或多个 {%[*] [width] [{h | l | I64 | L}]type | ' ' | '/t' | '/n' | 非%符号}
注:
1、 * 亦可用于格式中, (即 %*d 和 %*s) 加了星号 (*) 表示跳过此数据不读入. (也就是不把此数据读入参数中)
2、{a|b|c}表示a,b,c中选一,[d],表示可以有d也可以没有d。
3、width表示读取宽度。
4、{h | l | I64 | L}:参数的size,通常h表示单字节size,I表示2字节 size,L表示4字节size(double例外),l64表示8字节size。
5、type :这就很多了,就是%s,%d之类。
6、特别的:%*[width] [{h | l | I64 | L}]type 表示满足该条件的被过滤掉,不会向目标参数中写入值
支持集合操作:
%[a-z] 表示匹配a到z中任意字符,贪婪性(尽可能多的匹配)
%[aB'] 匹配a、B、'中一员,贪婪性
%[^a] 匹配非a的任意字符,贪婪性
例子:
1. 常见用法。
char buf[512] ={0} ;
sscanf("123456 ", "%s", buf);
printf("%s/n", buf);
结果为:123456
2. 取指定长度的字符串。如在下例中,取最大长度为4字节的字符串。
sscanf("123456 ", "%4s", buf);
printf("%s/n", buf);
结果为:1234
3. 取到指定字符为止的字符串。如在下例中,取遇到空格为止字符串。
sscanf("123456 abcdedf", "%[^ ]", buf);
printf("%s/n", buf);
结果为:123456
4. 取仅包含指定字符集的字符串。如在下例中,取仅包含1到9和小写字母的字符串。
sscanf("123456abcdedfBCDEF", "%[1-9a-z]", buf);
printf("%s/n", buf);
结果为:123456abcdedf
5. 取到指定字符集为止的字符串。如在下例中,取遇到大写字母为止的字符串。
sscanf("123456abcdedfBCDEF", "%[^A-Z]", buf);
printf("%s/n", buf);
结果为:123456abcdedf
6、给定一个字符串iios/12DDWDFF@122,获取 / 和 @ 之间的字符串,先将 "iios/"过滤掉,再将非'@'的一串内容送到buf中
sscanf("iios/12DDWDFF@122", "%*[^/]/%[^@]", buf);
printf("%s/n", buf);
结果为:12DDWDFF
7、分解key1088@163.com
sscanf("key1088@163.com","%[^@]%*c%s", user, host);
结果为:user=key1088,host=163.com

在ANSI标准中,signal()的声明如下:
void (*signal(int sig,void (*func)(int)))(int)
signal是一个函数,它返回一个函数指针,后者所指向的函数(signal的返回值)接受一个int参数并返回void。signal函数有两个参数,一个是sig(为int类型),另一个是func(为void(*)(int)类型)。
void (*func)(int)是一个函数指针,所指向的函数接受一个int参数,返回值是void。
下面用typedef进行简化:
typedef void(*ptr_to_func)(int);
ptr_to_func signal(int,ptr_to_func);
网上的一个例子:

#include 
enum { RED, GREEN, BLUE };
void OutputSignal(int sig)
{
    printf("The signal you /'ve input is: ");
    switch(sig)
    {
    case RED:
        puts("RED!");
        break;
    case GREEN:
        puts("GREEN!");
        break;
    case BLUE:
        puts("BLUE!");
        break;
    }
}
void ( *signal( int sig, void (*func)(int) ) ) (int)
{
    puts("Hello, world!");
    func(sig);
    return func;
}
int main(void)
{
    (*signal(GREEN, &OutputSignal))(RED);
    return 0;
}
Output:
Hello, world!
The signal you 've input is: GREEN!
The signal you 've input is: RED!