星期二, 十月 24, 2006
给控件做数字签名之三:进行数字签名 - 阿泰的软件实用主义 - 博客园
文中提到的数字签名工具包,请在此处下载
http://www.cnblogs.com/Files/babyt/SignTool.rar
至此,数字签名完成
在DOS窗口下,输入
chktrust.exe E:\myTest\08\Package\WebRTF.CAB
对我们的成果进行检验
此时成功,对了,这个“恭喜”的红字是我做上去的,可别到时候这俩字出不来还觉得奇怪
最后就是发布了
将这两个文件拷贝到WEB目录下进行测试,出现证书安装提示后按是安装即可
"
星期二, 十月 17, 2006
请教如何获得所有当前用户可以访问的,不是系统表的表名和列名? - ITPUB论坛
FROM all_col_comments
WHERE OWNER NOT IN('SYS','SYSTEM');"
如何有效地利用oracle的数据字典
数据字典里存有用户信息、用户的权限信息、所有数据对象信息、表的约束条件、统计分析数据库的视图等。我们不能手工修改数据字典里的信息。很多时候,一般的ORACLE用户不知道如何有效地利用它。
dictionary 全部数据字典表的名称和解释,它有一个同义词dict
dict_column 全部数据字典表里字段名称和解释
如果我们想查询跟索引有关的数据字典时,可以用下面这条SQL语句:
SQL>select * from dictionary where instr(comments,'index')>0;
如果我们想知道user_indexes表各字段名称的详细含义,可以用下面这条SQL语句:
SQL>select column_name,comments from dict_columns where table_name='USER_INDEXES';
依此类推,就可以轻松知道数据字典的详细名称和解释,不用查看ORACLE的其它文档资料了。
下面按类别列出一些ORACLE用户常用数据字典的查询使用方法。
一、用户
查看当前用户的缺省表空间
SQL>select username,default_tablespace from user_users;
查看当前用户的角色
SQL>select * from user_role_privs;
查看当前用户的系统权限和表级权限
SQL>select * from user_sys_privs;
SQL>select * from user_tab_privs;
二、表
查看用户下所有的表
SQL>select * from user_tables;
查看名称包含log字符的表
SQL>select object_name,object_id from user_objects where instr(object_name,'LOG')>0;
查看某表的创建时间
SQL>select object_name,created from user_objects where object_name=upper('&table_name');
查看某表的大小
SQL>select sum(bytes)/(1024*1024) as size(M) from user_segments where segment_name=upper('&table_name');
查看放在ORACLE的内存区里的表
SQL>select table_name,cache from user_tables where instr(cache,'Y')>0;
三、索引
查看索引个数和类别
SQL>select index_name,index_type,table_name from user_indexes order by table_name;
查看索引被索引的字段
SQL>select * from user_ind_columns where index_name=upper('&index_name');
查看索引的大小
SQL>select sum(bytes)/(1024*1024) as size(M) from user_segments where segment_name=upper('&index_name');
四、序列号
查看序列号,last_number是当前值
SQL>select * from user_sequences;
五、视图
查看视图的名称
SQL>select view_name from user_views;
查看创建视图的select语句
SQL>select view_name,text_length from user_views;
SQL>set long 2000;说明:可以根据视图的text_length值设定set long 的大小
SQL>select text from user_views where view_name=upper('&view_name');
六、同义词
查看同义词的名称
SQL>select * from user_synonyms;
七、约束条件
查看某表的约束条件
SQL>select constraint_name, constraint_type,search_condition, r_constraint_name from user_constraints where table_name = upper('&table_name');
SQL>select c.constraint_name,c.constraint_type,cc.column_name
from user_constraints c,user_cons_columns cc
where c.owner = upper('&table_owner') and c.table_name = upper('&table_name')
and c.owner = cc.owner and c.constraint_name = cc.constraint_name
order by cc.position;
八、存储函数和过程
查看函数和过程的状态
SQL>select object_name,status from user_objects where object_type='FUNCTION';
SQL>select object_name,status from user_objects where object_type='PROCEDURE';
查看函数和过程的源代码
SQL>select text from all_source where owner=user and name=upper('&plsql_name');
九、触发器
查看触发器
set long 50000;
set heading off;
set pagesize 2000;
select
'create or replace trigger ' ||
trigger_name || '' || chr(10)||
decode( substr( trigger_type, 1, 1 ),
'A', 'AFTER', 'B', 'BEFORE', 'I', 'INSTEAD OF' ) ||
chr(10) ||
triggering_event || chr(10) ||
'ON ' || table_owner || '.' ||
table_name || '' || chr(10) ||
decode( instr( trigger_type, 'EACH ROW' ), 0, null,
'FOR EACH ROW' ) || chr(10) ,
trigger_body
from user_triggers;
星期四, 十月 12, 2006
上机必读 二级上机考试部分评分方法
自动评分系统有客观、公正的优点,但也有死板的缺点,要想得到比较好的分数,应当考虑到机器 的这一特点。实际考试还有人工复查一项,由省级考试部门负责进行.但是人工复查如何进行,我们完全不得而知。因此我们下面的所有内容均不含人工复查内容, 仅从考试系统本身来进行分析和说明。
我们从多次使用中摸索到的考生可能感兴趣的几点介绍如下:
1. DOS操作题的评分比较复杂,评分系统在几次考试中标准似乎有一些变化。
按系统的操作说明,只要命令正确即可得分,但实际情况并非如此。机器评分只根据结果,结果正确即得分,命令正确而结果不正确,不能得分。
要注意使用规定的命令。比如考试系统不允许使用 deltree 命令,您如果习惯于用该命令来删除子目录,考试时将无法使用。
本人曾做过试验,将结果做得完全符合要求,而不让考试系统看到我所作的事(比如使用另外的工具来做),结果照样得分;而使用正确的命令(即使与答案完全相同),而结果不正确(自然使用了"不正当"的方法),评分结果是不能得分。
2. 程序修改题的评分大约有下面一些特点:
有结果输出到文件中的,先检查结果文件。如果结果文件内容完全正确,给满分,并不再检查修改内容。
结果没有输出到文件,或结果文件不正确的,逐个错误语句进行检查。分数平均分配(如果共有两个错误,每修正一个得15分;共有三个错误,则每修正一个得10分……)。
检查标志为"***found***"。即机器死板地检查第X个"***found***"下面第N行(第X个错误语句应在的行)是否修改得和标准答案中的一个相同,相同则给分,否则不给分。
例如:您的修改是完全正确的,与标准答案也完全一致。但是您插入了一个空行在"***found***"和修改了的行之间,这显然不影响程序的正确性,但自动评分系统却会认定您"修改错误"。
更有甚者:如果您在程序的前面增加一个含有"***found***"的注释行,则不论您的程序修改得有多正确,评分系统会毫不留情地给您一个零分。
程序修改题中还应注意考虑原程序作者的思路,所作改动应尽量小。
这里有一个极端的例子:(1999年上半年二级BASIC)
'* 给定程序MODI1.BAS其功能是: 从键盘上每次输入两个100以下
'* 的正数分别赋给Y和Z(如不符合此条件的, 则重新输入),累加到累
'* 加器X中,直到X的值超过500为止。请找出程序中的错误,将程序调
'* 试出所需结果。
'* 注意: 不得增行或删行, 也不得更改程序的结构!
X = 0
DO
DO
t = 0
INPUT "Y,Z="; Y, Z
IF 0 < Y AND Y < 100 AND 0 < Z AND Z < 100 THEN
t = 2
ELSE
PRINT "Out of Range! Input again"
END IF
'**********found**********
LOOP WHILE t <> 1
X = X + Y + Z
'**********found**********
'WHILE X <> 500
PRINT "X="; X
END
这里共有两个错误:第一个为条件错,第二个语句和条件均有错。因此第一个错误可只改动条件为 t<>2 或 t=0,整个语句为
loop while t<>2 或者 loop while t=0
第二个错误可改为
LOOP WHILE X <= 500
总之,这里的思路就是用 DO ... LOOP WHILE <条件> 语句。
如果使用 do ... loop until <条件>,程序可以同样成立。如第一个错误改为
loop until t=2
运行结果完全相同。
但是自动评分系统会认为您"修改错误!"扣掉您应得的15分!!!
过去 C 语言的考试题目一般都出的较为严谨,很少有错误发生(但2002上半年的题虽然没发现什么严重错误,其质量实在不敢恭维)。但在2001年下半年中,仍有错判现象。举一例如下:
/*
给定程序MODI1.C中函数fun的功能是:先将在字符串s中的字符
按逆序存放到t串中,然后把s中的字符按正序连接到t串的后面。
例如:当s中的字符串为:"ABCDE"时,
则t中的字符串应为:"EDCBAABCDE"。
请改正程序中的错误,使它能得出正确的结果。
注意:不要改动main函数,不得增行或删行,也不得更改程序
的结构!
*/
#include <conio.h>
#include <stdio.h>
#include <string.h>
void fun (char *s, char *t)
{
/************found************/
int i,sl;
// int i;
/* 由于C语言对书写格式不作要求,本错误如改为 int i, 其结果显然也是
正确的。然而遗憾的是,自动批改系统此时会判错! */
sl = strlen(s);
for (i=0; i < sl; i++)
/************found************/
t[ i ] = s[sl-i-1];
// t[i] = s[sl-i];
for (i=0; i t[sl+i] = s[i];
t[2*sl] = '\0';
}
main()
{ char s[100], t[100];
clrscr();
printf("\nPlease enter string s:"); scanf("%s", s);
fun(s, t);
printf("The result is: %s\n", t);
}
有的考生怕修改过程中忘记了原来的内容,把原来的内容用注释的方法保留在程序中(应该说,这是一个好的习惯)。比如把上面的内容写成
t[ i ] = s[sl-i-1]; // t[ i ] = s[sl-i]; 或者
t[ i ] = s[sl-i-1]; /* t[ i ] = s[sl-i]; */
毫无疑问,这是正确的。但是评分系统竟然会判为"错误",不给分。考试系统会出现这种低级错误,倒是我以前未曾想到的,而且直至目前,这种错误仍未得到修正。
因此考生必须注意把错误的内容全部删除掉。
3. 编程题除去少部分类似填空或改错的BASIC程序外,均有结果输出到文件。自动评分时检查结果文件,如果结果文件内容正确,则给满分;如果没有结果文件 (即使程序是正确的,但没有运行),则得零分;如果应有若干个结果,则得分一般按结果数平均分配(比如应有两个结果,其中一个正确,另一个错误,则一般可 得40/2=20分)。在多数情况下,编程题往往不是满分就是零分。
要注意的是,在FoxBASE编程题中,如果要生成新的数据库,只要库结构正确,哪怕其他都是错误的,也可得10到20分(随题目不同而有所变化)。因此做不到编程题的考生不可轻言放弃。
部分BASIC的编程题实际上是填空题,因此是一个个空来改的,分数按空数平均分配。与程序修改题不同的是,它没有使用"***found***"标记,即使有添行等,也能正确进行评分。
有的编程题对考生提出了一些限制,比如不许使用某个或某类函数,或不许使用某种方法等。在评分时,却很可能没有考虑如何限制这一点。我曾试过专门用"不 许"的方法去做题,在结果正确的情况下,照样得满分。看来考试系统也是"撑死胆大的,饿死胆小的"。当然,本人绝不鼓励考生不按要求做。如果你看了我的贴 子,去做一个"胆大的",得不到分可不要找我负责哟!!!
首先,我讲一下考试评分系统的工作原理:
考试评分系统是不看源程序。而是对你的源程序编译时所产生的.obj文件和.exe文件进行测试。测试分为两部份组成:
一、运行:完成输入、输出。
二、评分:与预期的结果对比。
运行:
1、运行.exe文件(由你的源程序生成的),运行时,它会调用一个读函数,把in.dat文件里的测试数据读入主函数;一般二级有20组数据,三级、四是一大组数据(一篇英文、400个四位数、100个记录等)
2、调用你所编写的函数,把这些数代入。
3、调用写函数,把运行结果写入out.dat文件里。一般二级有20行结果(就是每组数据的运行结果),三级、四级有一大组结果(如一组字符流)或二到三个结果(如求平均值、公差、符合条件的数的个数等)
以上这三个过程二级里是调用NONO函数完成,三级、四级是分别调用ReadDat()和WriteDat()函数来完成。
评分:
运行test.exe文件,把out.dat文件里的内容与评分系统内的内容(预期结果)比较,在二级里,每对一行(就是这组数据的测试结果),给5分。
三级、四级的就要看具体情况给分了,如:字符流处理的,那只要错一个小部分就0分,因为字符流是连续的。如果是数值处理的(有2-3个结果),那就是 每对一个结果结20-30分,但错了一个答案就很难及格了,因为数值处理很多数是互相关联的,如:求平均值,如果符合条件的数的个数错了,那平均值也一定 是错的。还有那个100个记录的,那它是以那一行上的内容是不是与预期的一样,每对一行给1分。(因为这个测试数据刚好一百行),这就是三级或四级里有: 0<成绩<100 分的原故。(很多人都说三级四级上机成绩不是0分就是一百分,这个观点是错的)
以上文件名、函数名应以源程序调用时的名为准。
由上述可知:一个题如果通过编译、能运行就一定有分,那是错的,因为一个题,如果你一点都不做(放空),那是一定能通过编译和运行的。但这时,out.dat文件为空,如果你编写了程序,而运行的结果都是错的,那和空是一样的。这样是不能得分的。
还有是有人说我做了题,通过了编译,也出了"正确"结果,那为什么会不及格呢?是不是考试系统有问题,这个可能很小,一般是因为你的程序有问题,如以前考网上有一个题:
求一子字符串在主字符串出现的次数;
例如:子串:go
主串:good yjgocel liugo ygoygong
结果为: 5
以下是两个人的回复:
一、int fun(char *str,char *s)
{
int m=0;
char *p=s;
while(*str!='\0')
{ if(*str==*p)
{ str++;
p++;
} /*两字符相同就同时移动指针。*/
else
{p=s;
str++ ; /*不同只移动一个指针,并把另一指针指向初始位置 */
}
if(*p=='\0') /*如果是连续的同时移动到了后一个字符串尾,就计一次数 */
{ m++;
p=s ;
}
}
return m;
}
二、int fun(char *str,char *s)
{
int i,j,m=0;
for(i=0;i<strlen(str);) {
for(j=0;j<strlen(s);)
if(str[i]==s[j]) {
i++;
j++;
}
else {
i++;
break;
}
if(j==strlen(s))
m++;
}
return m;
}
其实这两个答案,对于上面的那个主串和子串也许是可以的,但,如果主串是aaa aa,子串是aa,那上面这两个程序就不行了,因为,aa在aaa aa里出现了3次,而不是2次,字符串是可以嵌套出现的,而测试数据里的数据一般什么情况都有,而象这种嵌套的多,这就是他认为自已程序是对的,而结果是 不及格的原故。
以上两位如果是考生的话,他们肯定会说他们的程序是绝对对的,是评分系统问题。
正确的应这样写:
fun(char *str,char *s)
{char str1[10]="";
int i,k=0;
for(;*str;str++)
{for(i=0;i<strlen(s);i++)
str1[i]=*(str+i);
if(!strcmp(str1,s)) k++;
}
return k;
}
下面我再讲一个测试上述程序的实例:
星期一, 十月 09, 2006
共享软件防破解的实用招法
1、检测主程序大小,防止破解补丁之类: Function TForm1.GesSelfSf: integer; var F: file of byte; begin Filemode:=0; Assignfile(F,'.\FileName.exe'); Reset(f); Result:=Filesize(F); Closefile(F); end; 2、检测创建日期和时间,让破解补丁实效: Function TForm1.FinDate:String; var t:TDate; begin ShortDateFormat:='yyyy-mm-dd'; t:=FileDateToDateTime(FileAge('FileName.exe')); Result:=DateToStr(t); end; 3、注册码加密函数嵌入数学函数,增加破解难度: (略) 4、必要时自己删除自己(主程序): procedure TForm1.Funll; var hModule:THandle; buff:array[0..255]of Char; hKernel32:THandle; pExitProcess,pDeleteFileA,pUnmapViewOfFileointer; begin hModule:=GetModuleHandle(nil); GetModuleFileName(hModule, buff, sizeof(buff)); CloseHandle(THandle(4)); hKernel32:=GetModuleHandle('KERNEL32'); pExitProcess:=GetProcAddress(hKernel32, 'ExitProcess'); pDeleteFileA:=GetProcAddress(hKernel32, 'DeleteFileA'); pUnmapViewOfFile:=GetProcAddress(hKernel32, 'UnmapViewOfFile'); asm LEA EAX, buff PUSH 0 PUSH 0 PUSH EAX PUSH pExitProcess PUSH hModule PUSH pDeleteFileA PUSH pUnmapViewOfFile RET end; begin Funll; end; end; 具体怎么使用,那要看你自己的意愿了和需要了。反正我是这样做的,我的软件ADSL拨号计时器只在很早版本上出过注册机,后来的v3.70出过破解补丁 ——其实只是破掉了启动时提示注册的对话框,实质上根本没破解。用了上述的着法以后,到现在的v5.28版本,再没有过什么破解补丁或注册机。 如果现在的v5.28版本谁能破解,将立即公布程序源码。 附:注册机破解法的原理以及应对方法 认识注册机破解法 顾名思义,写注册机来破解软件注册的方法,就是模仿你的注册码生成算法或者逆向注 册码验证算法而写出来的和你一模一样的注册机。如果被写出注册机,你的软件只好免费了。或者你必须更换算法,但以前注过册的合法用户都得被迫更换注册码了。 Cracker要写注册机必须详细研究你软件的验证模块,这必须先将你的软件脱壳,再反汇编或者用调试器跟踪。市面上许多加壳和保护软件都吹嘘不可能被 脱壳,但到目前为止没有一个软件兑现了自己的诺言。由于CPU最终执行的都是有效指令,所以等你的程序自解压完成后再从内存中Dump出来就可以实现脱 壳。因此不要在壳上面花很多功夫,因为没有这个必要。 第一招:制造假相 反汇编和调试器跟踪都是不可能防止的,因为所有的Win32程序都必须通过API来调用Windows系统中的关键DLL的(如Kernel32.dll、GDI32.dll等),然而API是可以Hook的。我们只能从自己的代码着手来保护我们的劳动果实了。 为了自己调试和以后维护的方便,我们一般采用有意义的名字给我们的函数命名,可这给了Cracker可乘之机。例如这样的函数是什么意思大家应该一目了 然吧?IsRegistered(),IsLicensed(),LicenseVerify(),CheckReg()……这样Cracker就可以轻 松地从数千个函数中找到他的目标——你的注册码校验函数!而且破解Delphi编写的软件还有一件TMG小组的破解利器——DeDe。它可以轻松地看到你 软件里的Form、Unit和函数名,还可以反汇编一部分代码,更可以和Win32DASM合作反汇编更多的代码,对Delphi编出的程序威胁极大。 为了不给Cracker创造温馨舒适的破解环境,要故意混乱(Obfuscate)我们的代码,将软件中所有的函数名全部替换成随机 生成的函数名。例如Func_3dfsa_fs32zlfv这个函数是什么意思?恐怕只有天知道了。网上有现成的代码混乱器,按你使用的编程语言的种 类可以找到一些。但要注意,只有当你要发布软件时才使用它,而且一定注意备份源代码。否则,当你看不懂你自己的代码时就着急了:) 第二招:用公匙,并改名 另外,一定要使用公开密匙算法保护你的软件。RSA、DSA和El Gamal之类的算法都可以从网上找到。但注意:将你算法单元中所有涉及到算法名称的字符串全部改名。避免被Cracker发现你用的算法而模仿写出注册 机来!你还可以张冠李戴,明明用的DSA,将名字全部替换成RSA。 其它算法,如对称算法和Hash算法也要注意改名,否则这样: EncryptedCode = Blowfish(MD5(UserName),MD5(Key)); //你的加密算法,使用了Blowfish(对称算法)和MD5(Hash算法) 虽然那些Cracker不了解Blowfish和MD5算法的原理,也不会逆向推测它们,但他们了解你的校验算法的流程和算法名,便可马上从网上找到类似的Blowfish和MD5算法包,从而模拟你的软件仿造出注册机。 如果你用不常见的,算法如Skipjack(NASA美国航天局标准算法)、LOKI、3-WAY、Safer之类不出名但保密程度很高的算法,并且全部改名,这样就会伤透他们脑筋了。 当然,最好把Hash算法也全部改名,会给他们制造更多的困难。但注意,MD5和SHA之类的Hash初始值会被Cracker从内存中找到,这样他就 知道你用的Hash了。所以建议同时使用MD5的变形算法Ripe-MD(RMD)128或160或其它的Hash,如Tiger、Haval等算法。 第三招:阻止别人调试 还有一点,调试器对我们的威胁很大,我们不会让Cracker们舒舒服服地使用SoftICE、TRW或OllyDbg来调试我们的程序。除了常用的MeItICE方法外,这里我给一个笔者写的方法: {检查自己的进程的父进程是否为Explorer.exe,否则是被调试器加载了} {不过注意,控制台程序的父进程在WinNT下是Cmd.exe!} {注意加载TlHelp32.pas单元} procedure CheckParentProc; var //检查自己的进程的父进程 Pn: TProcesseNtry32; sHandle:THandle; H,ExplProc,ParentProc:Hwnd; Found:Boolean; Buffer:array[0..1023]of Char; Path:string; begin H:= 0; ExplProc:= 0; ParentProc:= 0; //得到Windows的目录 SetString(Path,Buffer) GetWindowsDirectory(Buffer,Sizeof(Buffer)- 1)); Path:= UpperCase(Path)+ '\EX PLORER.EXE';//得到Explorer的路径 //得到所有进程的列表快照 sHandle:= CreateToolHelp32Snap Shot(TH32CS_SNAPALL,0); Found:= Process32First(sHandle,Pn);//查找进程 while Found do //遍历所有进程 begin if Pn.szExeFile = ParamStr(0)then //自己的进程 begin ParentProc:= Pn.th32ParentProcessID://得到父进程的进程ID //父进程的句柄 H:= OpenProcess(PRO CESS_ALL_ACCESS,True,Pn.th32Parent ProcessID); end else if UpperCase(Pn.szExeFile)= Path then ExplProc:= Pn.th32ProcessID;//Ex plorer的PID Found:= Process32Next(sHandle,Pn);//查找下一个 end; //父进程不是Explorer,是调试器…… if ParentProc <> ExplProc then begin TerminateProcess(H,0);//杀之!除之而后快也! :) //你还可以加上其它什么死机代码来消遣消遣这位可爱的Cracker:) end� end � 你可以在Delphi或者VC中试试,这样可以把Delphi和VC杀掉了,因为你现在用的是Delphi和VC的内置调试器来运行你的程序。调试的时候你还是把它的注释删掉吧,发布时别忘记激活哟! 第四招:保护字符串 最后一个问题,这也是一个非常重要的问题:保护你的字符串!字符串在注册模块中非常重要!当一个富有经验的Cracker破解你的软件时,首先做的就是 窃取你的字符串。比如他会输入错误的注册码,得到你关于错误注册码的提示,通常是"无效的注册码,请重新输入!"或者"Invalid key(please input again)"等等,然后用OllyDbg进行断点调试或者用WinDASM、IDA Pro等静态分析工具在被他脱壳后的程序中查找那个字符串,找到后进行分析。因此,请一定加密你的字符串! 使用时再临时解密出来,而且要尽量少使用消息提示框,避免被Cracker找到漏洞。加密字符串不需要太复杂的算法,随便找一个快速的对称算法就可以了。 最后提醒大家一句,不要在加密上花太多的功夫!你应该把更多的时间和精力都用来完善你的软件,这样会更合算。借用一位前辈的话来忠告 大家吧:花点时间考虑你自己的软件,看看它是否值得保护?如果没人用你的软件,保护也就没有意义了,不要过高估计你的软件"对世界的重要性 | |||||
|