|
[原创]新手学习计划
第三章.数据和C 1.最小的存储单位称为位(bit),可以容纳两个值(0或1)之一。1个字节均为8位,包含256种0、1组合。 在OD下能看到内存区域,但都是十六进制显示的,其实只是一个表现上的不同,实际存储都是0、1这样的位信息。 2.计算机使用补码进行存储。 正数的原反补码都是相同的,负数则是原码求反加一。这个过程据说是大学计算机第一节课的内容,我自己也学习了一下,算是理解了。 3.int __cdecl printf(const char *, ...); printf可变参数的实现主要是靠三个宏,计算出参数在堆栈中的地址,然后printf会申请新的缓冲,将%格式说明符替换,最后进行输出,刷新缓冲,显示相关字符。 typedef char * va_list; #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define va_end(ap) ( ap = (va_list)0 ) int __cdecl printf (const char *format, ...) { va_list arglist; int buffing; int retval; va_start(arglist, format); _ASSERTE(format != NULL); _lock_str2(1, stdout); buffing = _stbuf(stdout); retval = _output(stdout,format,arglist); _ftbuf(buffing, stdout); _unlock_str2(1, stdout); return(retval); } 关于这段,通过调试CRT源码,或者直接在OD下跟一下,可能会清晰一些。 具体内容可以参考这篇Blog,《printf原理与变参支持》 最近也一直在学习,只是有些太基础的内容,好理解,但是不好表述,就偷个懒,没有记录那么多。 2012/3/27 revfish |
|
[原创]新手学习计划
StartAoA说的在理,但是大神们首现要有时间,工作后空闲时间应该是很少的;其次工作中的研究毕竟事关相应的产品,可能会涉及到将同组别人的研究成果泄漏,也算是对同事的一种不尊重;最后,没有最后,觉得更多的时候还是需要自己来一步步的走。恩,作为新手少说话,多学习吧。 第二章.C语言概述 1.主函数int main(void) 由于使用VC来编译学习代码,就不去遵循什么C99标准了,main依然是C语言的默认入口函数。不过使用VC下的一个编译选项#pragma comment(linker,"/entry:EntryFunc"),可以修改入口函数,但是还会产生一些问题,这个以后遇到了再说吧。 2.【疑问】main函数是执行时第一个函数么? A1PASS当时写逆向三步走时,一开始就提出OD载入程序后,发现根本不是写的相关逻辑。这里自己也验证了一下,main函数调用前都做了什么。 大概就是这个过程,但是VC/VS各版本,包括Debug/Release,开启不同的优化编译选项出来的代码会有若干差异,这里忽略。 下列代码是从crt0.c拷贝来的,能够更好的理解mian函数执行前,都做了什么工作。 //ASCII控制台启动函数 void mainCRTStartup(void) { int mainret; _TUCHAR *lpszCommandLine; STARTUPINFO StartupInfo; //获取版本信息 _osver = GetVersion(); _winminor = (_osver >> 8) & 0x00FF ; _winmajor = _osver & 0x00FF ; _winver = (_winmajor << 8) + _winminor; _osver = (_osver >> 16) & 0x00FFFF ; //堆空间初始化 //MT为多线程标志 #ifdef _MT if ( !_heap_init(1) ) #else if ( !_heap_init(0) ) #endif fast_error_exit(_RT_HEAPINIT); //初始化多线程环境 #ifdef _MT if( !_mtinit() ) fast_error_exit(_RT_THREAD); #endif __try { //获取命令行 _acmdln = (char *)GetCommandLineA(); //获取环境变量信息 _aenvptr = (char *)__crtGetEnvironmentStringsA(); //获取命令行信息 _setargv(); //获取环境变量信息 _setenvp(); //初始化全局数据和浮点寄存器 _cinit(); __initenv = _environ; //调用main函数 mainret = main(__argc, __argv, _environ); //检查main函数返回值执行析构函数,或者atexit()注册的结束后运行函数 exit(mainret); } //异常处理 __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) ) { _exit( GetExceptionCode() ); } } 3.C99标准允许把声明放在代码块中的任何位置,但是首次使用变量之前仍然要声明。 #include <windows.h> #include <stdio.h> typedef int (WINAPI * AddProc)(int a, int b); int main() { HMODULE hInterfaceDLL; AddProc add; hInterfaceDLL = LoadLibrary("InterfaceDLL.dll"); add = (AddProc)GetProcAddress(hInterfaceDLL, "Add"); int i = 1; int j = 3; int s = add(i, j); printf("%d\n", s); return 0; } 先不看这段代码的具体含义,编译的时候无法通过编译(前提,VC下建立源文件时将后缀名改成.c,使之为标准C编译),VC提示如下: error C2143: syntax error : missing ';' before 'type' error C2143: syntax error : missing ';' before 'type' error C2143: syntax error : missing ';' before 'type' error C2065: 's' : undeclared identifier 但是使用CPP后缀就能够成功通过编译,现在想来就是这个原因吧,C99之前的标准需要在一开始声明变量,查询相关错误号,在微软网站上找到一句话 In Microsoft C, compiler errors C2143 and C2144 are defined as follows: 应该是使用了之前的K&R,C的标准,并不是ANSI定制的C99。 相对应改成如下就能够成功通过编译: int main() { int i = 1; int j = 3; int s; HMODULE hInterfaceDLL; AddProc add; hInterfaceDLL = LoadLibrary("InterfaceDLL.dll"); add = (AddProc)GetProcAddress(hInterfaceDLL, "Add"); s = add(i, j); printf("%d\n", s); return 0; } 4.操作系统和库通常使用一个或者两个下划线开始的名字,自己带应用代码中避免出现这种命名。 _CRTIMP void * __cdecl malloc ( size_t nSize ) { void *res = _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0); return res; } 这个是从C运行库中复制的,可以看出,使用了好多"_"为名称(宏名、调用约定名、函数名、结构名...)开始。 5.提高程序可读性的技巧,选择有意义的变量名,使用注释,使用缩进,使用空行分隔概念上的不同部分。 各个公司的代码风格应该是不相同的,但是有了自己的风格,还是更容易阅读代码。比如过evilor兄的《QQ游戏大厅的SX保护》代码读起来就很舒服,所以还是要养成一个良好的代码编写风格。 2012/3/24 revfish |
|
[原创]新手学习计划
不管是捧是杀都谢谢大家的回复,既然决定要走,起码要坚持一年,一起共勉吧。 随便在当当买了本纯粹讲解C语言的《C Primer Plus》,每天用一些时间来阅读,笔记就学习泉哥riusksk做成一条条Tips吧。 第一章.概览 1.C是为编程人员开发的语言。 愚见以为操作系统和编译器是很强大的两样东西,而C语言可以开发这两样东西。 2.C语言的设计特性自然地采用自顶向下的规划、结构化的编程,以及模块化的设计,使得编写出的程序更可靠、更易懂。 面向对象编程是一种哲学思想,将计算机代码抽象成为一个物件,具有自己的属性,也能够通过一些方法控制自己,对外留出一些接口,至于一些不想让别人知道的实现细节可以在内部实现。但是究其底层,语法特性是编译器在约束,到达汇编一层依然跳脱不了内存,寄存器。依然是一个个函数通过指针来操作内存中的数据块。所以C语言学习一下还是没有坏处的。 3.C语言程序结构紧凑运行速度快,表现出汇编语言才具有的精细控制能力。 编译型语言直接有编译器一次性制作成标准的可执行文件,能够在对应的平台直接执行。不需要解释器的逻辑去分析、转换、执行。尤其在开启优化选项后,阅读其反汇编代码会发现每一句都是有用的,而源程序中没有被利用到的地方,可能在反汇编代码中都找不到踪影。 4.编译器是将高级语言程序解释成计算机所需的详细机器语言指令集的程序。 5.使用C语言的7个步骤: 定义程序目标----设计程序----编写代码----编译链接----运行程序----调试和测试程序----维护和修改程序 其实每个步骤都存在一个小循环,一点点的优化整个步骤,就这个过程不敢有心得,毕竟还是一个初学的人。 6.将源文件转换成为可执行文件,需要经过编译和链接。编译器将源代码转换为中间代码,链接器将中间代码与其他代码相结合来生成可执行文件。 这个是从另一本书上截得图,GCC的编译过程,跟Windows差不多,能够帮助理解。 7.C的某些方面取决于系统,例如存储数字的空间,后续都是在Windows系统下,使用VC6.0进行学习。 第一章内容不多,但是还是需要认真对待的。笔记中如果哪点您认为有待商榷,可以帮我指出,我会虚心听您的指导的。快一点了,该休息了,明天再干一天,就能休息一下了。论坛的各位朋友晚安,Good luky。 2012/3/23 revfish |
|
[原创]新手学习计划
谢谢楼上的鼓励,就是你所说的,时间估计不够用,所以暂时没有办法学习数据结构了,先把这些基础知识都掌握了,后面会抽时间看的。 |
操作理由
RANk
{{ user_info.golds == '' ? 0 : user_info.golds }}
雪币
{{ experience }}
课程经验
{{ score }}
学习收益
{{study_duration_fmt}}
学习时长
基本信息
荣誉称号:
{{ honorary_title }}
能力排名:
No.{{ rank_num }}
等 级:
LV{{ rank_lv-100 }}
活跃值:
在线值:
浏览人数:{{ visits }}
最近活跃:{{ last_active_time }}
注册时间:{{ user_info.create_date_jsonfmt }}
勋章
兑换勋章
证书
证书查询 >
能力值