CI_Knight

且行善举,莫问前程。

0%

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 安装

参考

rsync 使用

当我还在使用 pycharm 做开发的时候,经常会使用 rsync 来同步本地和服务器上的代码,因为比传统的 scp 更为节省流量,只上传有改动的部分。

Usage

只简单介绍,毕竟文档是最好的老师。rsync 包括服务器端和客户端,服务器可以指定相应配置文件。

rsync –daemon –config=/path/to/rsyncd.conf

可以配置权限以及应用的启动信息。使用默认配置即可。

rsync 支持 ssh、scp 等文件传输方式,也可以直接使用 socket 连接来传输。那么举个例子(Unix 环境下)

rsync -avz -e “ssh -p $portNumber” user@remoteip:/path/to/ /local/path/

我使用 ssh 协议,将本地的 /local/path/ 同步到 远端服务器 /patg/to/ 下。

  • a 相当于 rlptgoD,r 是递归、l 是链接文件、p 表示保持文件原有权限、t 保持文件原有时间、g 保持文件原有用户组、o 保持文件原有属主、D 相当于块设备文件
  • z 传输时压缩
  • v 传输时的进度信息
  • e 制定使用 rsh,ssh 方式进行数据传输

rsync 算法

rsync 核心算法是 rolling checksum,核心在 rolling 上,把文件按照相同大小分块,然后分块 checksum,来比较每一块的 checksum 有没有改变。

如果这样,改变文件中间的一个字节,后面的每块都会改变。所以关键在意 rolling 上。当找不到匹配时,算法就要向后移一个字节。知道找到匹配为止。

不盗图了,传送门 https://coolshell.cn/articles/7425.html

如果是这样的话,当文件越多时,所需要花费的时间越长。同步代码使用还是可以的。如果是需要发布的代码还是建议使用 git hook。

部署工具介绍

Python 是可以直接运行一个 Python Web Server 的,Python -m SimpleHTTPServer 8000就可以启动一个监听 8000 端口的 Web Server,不像是 php 需要一个 Web Server来配合开发。

Python 的 Web 框架有很多,最具名气的是 Django,flask,tornado,web.py 等,当写一个小的项目的时候我们会直接通过框架提供的启动方式。当要正式部署一个 Web Server时并不能使用如此粗暴的方式,Server 很容易出现异常就挂掉。那么解决方案有很多。

以下是软件介绍,都可使用 pip 直接安装。

Supervisor

Supervisor 是很强大的进程管理工具,也是守护进程,帮你管理服务器上所运行的程序,守护程序防止被杀掉。可以通过写配置文件来批量启动你的 Web Server。

Gunicorn

一款 Wsgi HTTP Server,据说是比 uwsgi 更加高效,但是实测并没有 uwsgi 强。但是部署应用简单。

example: test.py

1
2
3
4
5
6
7
8
9
10
def app(environ, start_response):
"""Simplest possible application object"""
data = 'Hello, World!\n'
status = '200 OK'
response_headers = [
('Content-type','text/plain'),
('Content-Length', str(len(data)))
]
start_response(status, response_headers)
return iter([data])

gunicorn –workers=2 test:app

启动方便,具体参数请看 gunicorn 文档 http://docs.gunicorn.org/en/latest/

uWsgi

这是我要说的重点,自测吞吐量是其他两种部署方式的两倍。

使用 Flask,uWsgi 和 Nginx 来部署 Server

flask run.py

1
2
3
4
5
6
7
import Flask

app = Flask(__name__)

@app.route('/')
def index():
return "Hello World!"

uwsgi 支持 xml,json,ini 等多种配置文件,我们来配置 testapp.ini

uwsgi testapp.ini

1
2
3
4
5
6
[uwsgi]
socket = /var/run/testapp.sock
venv = /path/to/python
wsgi-file = run.py
callable = app
chmod-socket = 666

/var/run 必须有可写权限,chmod-socket 是避免 nginx 无法读写导致502错误,接下来配置nginx

nginx server.conf

1
2
3
4
5
6
7
8
9
server {
listen 80;
server_name localhost;

location / {
include uwsgi_params;
uwsgi_pass unix:/var/run/testapp.sock;
}
}

这样可以成功部署了,访问 curl http://localhost 输出 Hello World! 部署成功。

更多可以看文档https://uwsgi-docs.readthedocs.io/en/latest/

与 Nginx 配合使用效果更好

早起最流行的是 LAMP,记得初学 Linux 让我们编译 LAMP,一干就是一天。慢慢的 Shell 用的都很熟练了。但是 Apache 用起来就很复杂,第一次使用 Apache 和 Django 部署搞 wsgi_mod 花了很长时间。之后使用了 Nginx 才算是彻底在部署 Web Server 上解放。配置简单,部署方便,轻量且强大。

Nginx 是不可少的,路由管理、静态文件管理,Gzip,HTTPS、HTTP2/SPDY、ETAG 都需要 Nginx 来 handle。

测试

使用 ab 测试工具 ab -c 10 -n 100 http://localhost/ 模拟10人请求 localhost 100次。

守护进程

Web Server 使用 uwsgi 或者 gunicorn ,都是需要守护进程来守护 Server 不被杀掉。这时再使用 supervisor 就可以了。

这篇文章不是讲教你怎么搭建无线热点的,毕竟不是很难的东西,网上都可以搜到相关的博客,毕竟搭建一次写个脚本就可以了。

从 Mac 讲起

公司刚刚搬家,周围 WiFi 信号颇多,Mac 并没有有线网卡,无线真的是卡的要死,ping网关有时都能达到两万毫秒时,这种延迟是要命的,一般都会连到内网服务器上写代码,这种延迟都是会被卡掉的,要是玩游戏的话都可以摔键盘了。

使用网卡转USB

leader 一直是这样上网的,毕竟会比无线稳定很多,但是买转换器也是一笔不必要的支出。网上搜搜一般在三十块钱左右,并不知道好不好用。引入一样新的东西就会增加事物的复杂度。

使用无线路由器

家中有个闲置的无线路由器,在家只是做WDS桥接网络,未免有些浪费。想拿过来连接有线再单独开出来个私有的 WiFi,这样会比之前的稳定多,但是发射出来的 WiFi 信号未免会干扰其他信号,使得别人网络更加差劲。

树莓派搭建无线热点

这不是教程,我找到一篇不错的教程,也不至于再写一遍,只做一些提示。

我的是 raspberry pi 2,安装的 debian 的系统,这样的搭建方法也适用于基于 debian的一些系统,比如 ubuntu。

还有在设置 WIFI 信道的时候是很有讲究的,尽量使用范围内 WIFI 信号岔开5个信道的值,比如1,6,11。

搭建热点使用的软件基本上都是 hostapd,搭建方法应该也适用大多的 linux 发行版,在搭建前要注意自己的无线网卡型号,可以使用 lsusb、lsmod 来查看无线网卡的具体型号,我的是 RTL8188C,是支持开启 WIFI 热点的,但是 hotspot 是不支持的,需要替换成兼容版本。

下面这个教程步骤非常详细,特别提示也很多。

有疑问的话,可以直接在评论中讨论。