CI_Knight

且行善举,莫问前程。

0%

0x00

我说,如果想操纵时间那肯定要操纵空间。两量车,出发时间间隔20分钟,那么两车之间距离是是一定的,如果想超过前面的车就要加速度。追上前面车时,可以说空间相同,这时时间是否相同?我想不出来,也不知道该怎么研究,相对论、穿越时间太深奥了,不过相信有一天会做到的。

0x01

搞些区块链的东西,比如做个区块链象棋,发个代币,没给人初始都有一些代币,可以来下象棋,输的人要给赢的人一些代币,而且象棋的棋谱永远保存在区块链上,不会被篡改丢失。也可以搞搞区块链抽奖,用代币买随机号码,每天抽出幸运号码,给幸运者发奖励等等。总之这是个机会。

0x02

你能想多远就能走多远,比如我下象棋只能像后想三步,我看数字货币只能看到眼前的涨跌,自主思考才是最重要啊。走路走多了,停下来思考思考。

0x03

观察力还是很重要的,这个和个人脑力也有关,有的人一篇文章要看十分钟,有些人只要看五分钟,还比前者提取到到信息多,主要是人家还思考了呢。

0x04

羡慕那些有梦想的人。

0x05

羡慕那些有梦想,而且仍然在努力的人。

0x06

羡慕那些已经深陷梦想,而且仍然努力着的人。

有一个很经典的故事,斯坦门次为福特公司画了一条线,收了1000美元,其中画一条线的价值是1美元,知道在哪里画条线值999美元。这个故事让我深有感触。

前些天和同时排查一个问题数据库问题,我们staging环境有一个服务总是卡死,导致一些api超时无法访问,最终排查是数据库死锁,又经过一系列排查,具体到了一个函数内,这个函数中会先去获取一个数据库的advisory lock,然后再执行SQL,这一系列操作都在try cache中,也是为了方便回滚数据库,一切看起来都没问题。

为了复现这种情况,我们手动获取advisory lock,然后触发该函数,结果卡死。找不到具体原因,另一个同事看我们讨论激烈,过来询问并一语道破,这个数据库驱动是C写的,Python并不能抓取到C中的异常,所以会一直等待释放。

真是直接命中问题所在,和这个同事相比,不是经验问题,和我同岁,工作年限比我少,为什么他可以很快解决,而我并不能。

这是一个值得思考反思的问题。

偌大的上海繁华的不着边际,随便找出个的地方也能比我家强一些。

毕业两年,加上实习也有两年半了,待过北京跑过上海,浑浑噩噩的,我也许是在互联网圈子的朋友中混的最差的了,有过太多的错误决定,不成熟也不稳重。时间推移,急躁的心也变得平静。

没有例外,只能默默自许,还年轻,急躁不得。人生不公平,理想奢侈,遥不可及。

偌大的上海,在繁华的中心,来来往往的人,不知要走向何方。记不起当初的理想,也不知该走向何方。

最后只剩

低落

低落

低落。

然后又抬起头微笑。

人生公平,有失有得。人生苦短,唯有珍惜。何必羡慕,唯有努力,即便没有方向。

2016年的最后一篇文章,势必赶在最后的两小时前写完这篇文章。

ARP 欺诈

ARP 欺诈主要是在局域网内,通过伪造 IP 地址和 MAC 地址来达到欺诈的目的,并且会在网络中产生大量的 ARP 通讯,使网络瘫痪。攻击者只要持续不断的发出伪造的 ARP 响应包就能更改目标主机 ARP 缓存中的 IP-MAC 条目,造成网络中断或中间人攻击。

怎么实现 ARP 欺诈

在网络上搜索还是能搜到具体的方法的,在此只做总结,具体实现目前也没有研究过。仅供娱乐切勿违法。

欺诈前准备

一台接入路由器的电脑,路由器会分配给你内网 IP。电脑系统最好是 Linux ,如果是 windows 大概软件会更多。

一些软件

  • ettercaps,ARP 欺诈发包软件
  • driftnet,数据包图片显示软件

在 Ubuntu 下可以直接使用 apt 来安装

使用方法

ettercaps ARP欺骗之会话劫持

加入你连接路由的网卡是 eth0,网关为 10.0.0.1,那么

1
2
ettercap -i eth0 -T -M arp:remote /10.0.0.1/ // # 欺骗局域网内所有主机
ettercap -i eth0 -T -M arp:remote /10.0.0.1/ /10.0.0.12/ # 欺骗IP为10.0.0.12的主机

这是可以使用 tcpdump 对欺诈成功后发过来的包进行抓取,使用 tcpdump

1
tcpdump -i eth0

也可以使用 driftnet 实时显示图片。

如何防御

防御还是比较棘手的,造成网络拥堵的情况下只能找到发包的主机,还有就是要绑定自己电脑的网关地址。

Python解释器

有时候我们会把 Python 的 REPL (命令行下Python的交互环境)当作解释器,它会将源代码编译为字节码并执行。Python 解释器是一个模拟堆栈机器的虚拟机,仅使用多个栈来完成操作。也可以看看 500行实现一个解释器

在解释器接手之前,Python 会执行其他3个步骤:词法分析,语法解析和编译。这三步合起来把源代码转换成 code object,它包含着解释器可以理解的指令。而解释器的工作就是解释 code object 中的指令。

code object

Python字节码

在我们导入 python 脚本时在目录下会生成个一个相应的 pyc 文件,这是 python 解释器生成的字节码,是为了加速下一次的装载。

我们写一个简单的函数,并打印其字节码

dis

1
2
3
4
5
def sample(n:int) -> bool:
if n >= 1: return True
return False

print(sample.__code__.co_code)

sample.__code__ 是与其关联的 code object,而 sample.__code__.co_code 就是它的字节码。

输出:

b’|\x00\x00d\x01\x00k\x05\x00r\x10\x00d\x02\x00Sd\x03\x00S’

这是字节码组成的字节串,让我们把它转换成二进制

list(bytearray(sample.__code__.co_code)) [124, 0, 0, 100, 1, 0, 107, 5, 0, 114, 16, 0, 100, 2, 0, 83, 100, 3, 0, 83]

看,这写依然无法理解,这时我们借助标准库 dis(自节码反汇编器) 来查看字节码

dis.dis(sample)

1
2
3
4
5
6
7
8
9
10
2           0 LOAD_FAST                0 (n)
3 LOAD_CONST 1 (1)
6 COMPARE_OP 5 (>=)
9 POP_JUMP_IF_FALSE 16

3 12 LOAD_CONST 2 (True)
15 RETURN_VALUE

4 >> 16 LOAD_CONST 3 (False)
19 RETURN_VALUE

总共分为五列,分别是

  • 字节码对应的在源代码中的行号
  • 该字节码在字节码串中的第几个字节,也就是该字节码的索引
  • 字节码的人类可读的名字
  • 字节码参数
  • 字节码参数的内容提示

再看

dis.opname[124] ‘LOAD_FAST’ dis.opname[100] ‘LOAD_CONST’

这样我们就可以和之前的字节码对应了。当然这还没有完,我们还不理解这些操作码代表什么含义,打开 python文档 搜索 LOAD_FAST,你可以看到是将 co_varnames[var_num] 放进堆栈中(更高级的目前我也是看不懂),

Python 使用两个字节表示指令参数,如果Python使用一个字节,每个 code object 你只能有256个,而用两个字节,就增加到了256的平方,65536个

Frame

Frame 包含了一段代码运行所需要的信息与上下文环境。Frame 在代码执行时被动态地创建与销毁,每一个 Frame 的创建对应一次函数调用,所以每一个 Frame 都有一个 code object 与其关联,同时一个code object 可以拥有多个 Frame,因为一个函数可以递归调用自己多次。

比如你有一个函数递归的调用自己10次,这时有11个 frame。总的来说 Python 程序的每个作用域有一个 frame,比如每个 module、每个函数调用、每个类定义。这跟数据栈是不同的。

未完待续

It’s interesting

Python 扩展

Python 和 C 粘合性很好,用 C 给 Python 添加扩展一般是性能问题,另外就是想要加密部分可以编译成二进制,保证源码不会泄露。

C Extending Moudle

C 扩展大概就是使用 Python 提供的方法将 C 代码在封装一遍。Python 提供了 Python.h 头文件,使用这些接口将 C 进行包装,最后编译成 so 文件(在windows下是dll)

编写 C 扩展需要三部分,缺一不可。

  • 导出函数
  • 方法列表
  • 初始化函数

Example

最主要的是先封装C函数,接下来举个例子,我的系统是 Ubuntu 14.04,Python2.7

定义函数

比方用 C 写一个两数相加的方法 plus,文件名为 sample.c

1
2
3
4
int plus(int n, int m)
{
return n + m;
}

导出函数

将该方法使用 Python 提供的API封装,首先导入头文件 Python.h

1
2
3
4
5
6
7
8
9
10
#include <Python.h>

static PyObject* wrap_plus(PyObject* self, PyObject* args)
{
int n, m, result;
if (!PyArg_ParseTuple(args, "ii:plus", &n, &m))
return NULL;
result = plus(n, m);
return Py_BuildValue("i", result);
}

所有的导出函数都返回一个 PyObject 指针,如果对应的C函数没有真正的返回值(即返回值类型为void),则应返回一个全局的 None 对象(Py_None),并将其引用计数增 1

1
2
3
4
5
PyObject* method(PyObject *self, PyObject *args)
{
Py_INCREF(Py_None);
return Py_None;
}
  • PyObject 是一个能表示任何Python对象的C数据类型
  • PyArg_ParseTuple() 函数被用来将Python中的值转换成C中对应表示
  • Py_BuildValue() 函数被用来根据C数据类型创建Python对象
  • 更多接口查看文档

PyArg_ParseTuple 更多类型请看文档, ii,表示args的长度必须为2,且必须为int类型

方法列表

1
2
3
4
static PyMethodDef sampleMethods[] = {
{"plus", wrap_plus, METH_VARARGS, "Return n plus m"},
{NULL, NULL}
}
  • 方法列表中的每项由四个部分组成:方法名、导出函数、参数传递方式和方法描述
  • 方法名是从Python解释器中调用该方法时所使用的名字
  • 参数传递方式则规定了Python向C函数传递参数的具体形式,可选的两种方式是METH_VARARGS和METH_KEYWORDS
  • {NULL, NULL} 标识结束

初始化函数

1
2
3
4
5
void initsample()
{
PyObject* m;
m = Py_InitModule("sample", sampleMethods);
}

构造 module 也可以使用 PyModuleDef_HEAD_INIT 和 PyModule_Create(官方这么写的)

编译链接

gcc -fpic -c -I/usr/include/python2.7 -I /usr/lib/python2.7/config-x86_64-linux-gnu sample.c gcc -shared -o sample.so sample.o cp sample.so /python/python/site-packages/

或者使用 distutils 安装

参考