首页 -> 安全研究
安全研究
绿盟月刊
绿盟安全月刊->第18期->技术专题
作者:小四 < mailto: scz@nsfocus.com >
主页:http://www.nsfocus.com
日期:2001-02-05
Q: 为了避免shmget()不必要的失败,想在C代码中获取shmsys:shminfo_shmmax的值。
但是不能读取/etc/system,那样很不可靠。
set shmsys:shminfo_shmmax = 0x2000000
A: <hume.spamfilter@bofh.halifax.ns.ca>
首先执行如下shell命令
# echo 'shminfo_shmmax/D' | adb -k
physmem fddb
shminfo_shmmax:
shminfo_shmmax: 134217728
于是我们可以编写如下C代码
--------------------------------------------------------------------------
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <kvm.h>
#include <nlist.h>
#include <fcntl.h>
#define KERN_NAMELIST "/dev/ksyms"
/* should not be /dev/kmem */
#define KERN_CORE "/dev/mem"
int main ( int argc, char * argv[] )
{
kvm_t * krn = NULL;
struct nlist nms[2];
unsigned int val;
if ( ( krn = kvm_open( KERN_NAMELIST, KERN_CORE, NULL, O_RDONLY, argv[0] ) ) == NULL )
{
exit( -1 );
}
nms[0].n_name = "shminfo_shmmax";
nms[0].n_value = 0;
nms[0].n_type = 0;
nms[1].n_name = NULL;
nms[1].n_value = 0;
nms[1].n_type = 0;
if ( kvm_nlist( krn, nms ) == 0 )
{
if ( nms[0].n_type != 0 )
{
if ( kvm_read( krn, nms[0].n_value, ( char * )&val, sizeof( val ) ) != 4 )
{
fprintf( stderr, "Unable to fetch shminfo_shmmax.\n" );
}
else
{
fprintf( stdout, "shminfo_shmmax = %ld\n", val );
}
}
else
{
fprintf( stderr, "Unable to fetch shminfo_shmmax.\n" );
}
}
kvm_close( krn );
exit( 0 );
} /* end of main */
--------------------------------------------------------------------------
关于kvm_*()系列函数,可以man -s 3k kvm_nlist等等,但是Sun强烈反对利用
kvm_*()函数,几乎没有兼容性、可移植性可言。
A: scz <scz@nsfocus.com>
原代码有误,应该使用/dev/mem作为corefile,而不是/dev/kmem,上例已经做了
修改。编译命令如下:
Solaris 2.6/7 32-bit
gcc -O3 -o getshm getshm.c -lkvm
Solaris 7 64-bit
/opt/SUNWspro/SC5.0/bin/cc -xarch=v9 -O -o getshm getshm.c -lkvm
这个程序只能以root身份运行,应用受限。
顺便我们介绍Mark Henderson提供的sethostid.c,该代码用于修改Solaris 2.6/7系
统上的hostid,如果企图用于Solaris 7,必须用Workshop 5.0编译成64-bit应用程
序,否则无法成功。很多朋友抱怨过change-sun-hostid.tar.gz里的代码无法用于7,
正是这个毛病,我已经增加了64-bit编译注释。
--------------------------------------------------------------------------
/*
* Mark Henderson < mailto: mch@squirrel.com >
*
* 必须以root身份运行,至少拥有/dev/kmem的读写权限
*
* Solaris 2.6 32-bit
* gcc -O3 -o sethostid sethostid.c -lelf
*
* Solaris 2.7 64-bit
* /opt/SUNWspro/SC5.0/bin/cc -xarch=v9 -O -o sethostid sethostid.c -lelf
*
* 不带参数运行直接返回当前hw_serial
* 带参数运行则设置内存映像hw_serial,命令行参数采用16进制指定
*
* June 1996
*/
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <nlist.h>
int main ( int argc, char * argv[] )
{
struct nlist nl[2];
int kmem;
off_t where;
unsigned int new_hostid; /* scz: 这里必须避免使用u_long,64-bit问题 */
u_char hw_serial[12];
u_char new_hw_serial[12];
if ( ( kmem = open( "/dev/kmem", O_RDWR ) ) < 0 )
{
fprintf( stderr, "cannot open /dev/kmem\n" );
exit( 1 );
}
nl[0].n_name = "hw_serial";
nl[1].n_name = NULL;
if ( nlist( "/dev/ksyms", nl ) < 0 )
{
fprintf( stderr, "cannot read namelist out of /dev/ksyms\n" );
exit( 1 );
}
if ( ( where = nl[0].n_value ) == 0 )
{
fprintf( stderr, "unknown kernel variable hw_serial\n" );
exit( 1 );
}
if ( lseek( kmem, where, SEEK_SET ) == -1 )
{
fprintf( stderr, "lseek on /dev/kmem failed\n" );
exit( 1 );
}
if ( read( kmem, ( char * )&hw_serial[0], 12 ) < 12 )
{
fprintf( stderr, "read from /dev/kmem failed\n" );
exit( 1 );
}
if ( lseek( kmem, where, SEEK_SET ) == -1 )
{
fprintf( stderr, "lseek on /dev/kmem failed\n" );
exit( 1 );
}
fprintf( stderr, "current hostid is 0x%08x\n", strtoul( hw_serial, NULL, 10 ) );
if ( argc > 1 )
{
if ( lseek( kmem, where, SEEK_SET ) == -1 )
{
fprintf( stderr, "lseek on /dev/kmem failed\n" );
exit( 1 );
}
new_hostid = strtoul( argv[1], NULL, 16 );
fprintf( stderr, "setting hostid to 0x%08x\n", new_hostid );
sprintf( ( char * )&new_hw_serial, "%u", new_hostid );
if ( write( kmem, ( char * )&new_hw_serial[0], strlen( new_hw_serial ) + 1 )
< strlen(new_hw_serial) + 1 )
{
fprintf( stderr, "write to /dev/kmem failed\n" );
exit( 1 );
}
}
close( kmem );
return( 0 );
} /* end of main */
--------------------------------------------------------------------------
下面我们用kvm_*()改写一下上述代码,做个对比。
--------------------------------------------------------------------------
/*
* flamez - Mark Henderson < mailto: mch@squirrel.com >
* greetz - < mailto: hume.spamfilter@bofh.halifax.ns.ca >
* creditz -
*
* scz < mailto: scz@nsfocus.com >
*
* 必须以root身份运行,至少拥有/dev/kmem的读写权限
*
* Solaris 2.6 32-bit
* gcc -O3 -o sethostid sethostid.c -lkvm
*
* Solaris 2.7 64-bit
* /opt/SUNWspro/SC5.0/bin/cc -xarch=v9 -O -o sethostid sethostid.c -lkvm
*
* 不带参数运行直接返回当前hw_serial
* 带参数运行则设置内存映像hw_serial,命令行参数采用16进制指定
*
* Feb 2000
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <kvm.h>
#include <nlist.h>
#include <fcntl.h>
#define KERN_NAMELIST ""
#define KERN_CORE ""
int main ( int argc, char * argv[] )
{
kvm_t * kmem = NULL;
struct nlist nl[2];
u_char hw_serial[12];
u_char new_hw_serial[12];
unsigned int new_hostid; /* scz: 这里必须避免使用u_long,64-bit问题 */
if ( ( kmem = kvm_open( "/dev/ksyms", "/dev/mem", NULL, O_RDWR, argv[0] ) ) == NULL )
{
exit( -1 );
}
nl[0].n_name = "hw_serial";
nl[0].n_value = 0;
nl[0].n_type = 0;
nl[1].n_name = NULL;
nl[1].n_value = 0;
nl[1].n_type = 0;
if ( kvm_nlist( kmem, nl ) == 0 )
{
if ( nl[0].n_type != 0 )
{
if ( kvm_read( kmem, nl[0].n_value, ( char * )&hw_serial, sizeof( hw_serial ) )
!= sizeof( hw_serial ) )
{
fprintf( stderr, "Unable to fetch hw_serial.\n" );
}
else
{
fprintf( stdout, "current hostid is 0x%08x\n", strtoul( &hw_serial, NULL, 10 ) );
if ( argc > 1 )
{
new_hostid = strtoul( argv[1], NULL, 16 );
fprintf( stderr, "setting hostid to 0x%08x\n", new_hostid );
sprintf( ( char * )&new_hw_serial, "%u", new_hostid );
if ( kvm_write( kmem, nl[0].n_value, ( char * )&new_hw_serial, strlen( new_hw_serial ) + 1 )
!= strlen( new_hw_serial ) + 1 )
{
fprintf( stderr, "write to /dev/kmem failed\n" );
}
}
}
}
else
{
fprintf( stderr, "Unable to fetch hw_serial.\n" );
}
}
kvm_close( kmem );
exit( 0 );
} /* end of main */
--------------------------------------------------------------------------
个人不推荐在大型应用软件中使用kvm_*()系列函数。有些可配置系统参数可以通过
sysconf(3C)获取。
版权所有,未经许可,不得转载