about 46 results (0.01 seconds)

如何还原PyInstaller打包的可执行文件

by LauCyun May 6 15:12:24 12,314 views

前段时间,忙于应急驱动人生挖矿病毒,该病毒程序是用Python编写,然后通过PyInstaller打包成可执行文件(体积为7MB左右),然而可对其还原成Python源代码,为此将我所用的还原方法分享出来。

至于,想了解PyInstaller打包过程的小伙们,可阅读:PyInstaller打包exe文件

0x0 判断文件是否PyInstaller打包

将文件拖进IDA进行反编译,选择view -> open subview -> string提取文件中的字符串内容,如下图所示:


图1 字符串资源

如果有如图1所示的字符串,则说明这个文件是由由Python编写,然后通过Pyinstaller将其打包成可执行文件文件。

0x1 还原方法

目前,有两种方法可以还原成.py文件,具体如下:

1. python-exe-unpacker

使用方法很简单,直接执行命令python python_exe_unpack.py -i <待还原文件>即可还原,如下图所示:


图2 python-exe-unpacker还原过程

当然也有可能还原失败,不过绝大多数情况下是可以使用的,报错如下:


图3 还原失败

如果还原失败,那接着尝试第二种方法。

2. pyi-archive_viewer

通过查看PyInstaller的文档,发现它提供pyi-archive_viewer这样一款工具,它可以提取可执行文件中Python代码。

根据官网的介绍,它的作用就是查看可执行文件中Python代码,详细介绍可参考官方文档:https://pyinstaller.readthedocs.io/en/stable/advanced-topics.html#using-pyi-archive-viewer

注:需要安装PyInstaller才能使用pyi-archive_viewer工具。

执行如下命令,即可查看可执行文件中Python代码:


图4 查看可执行文件中Python代码

如图5所示,将列出pnwxb.exe文件中集成Python包,然后选择需要提取的文件(如:ii),提取命令如下图所示:


图5 提取.pyc文件

但是还有一个问题,就是PyInstaller在打包.pyc时,会把.pyc的magic和时间戳去掉,所以需要手工修复。

修复之前,先看一下正常.pyc文件的magic和时间戳,如下图所示:


图6 pyc文件格式

图6红框中的前4个字节为文件magic(03 F3 0D 0A),后4个字节为时间戳(随机即可),所以需在ii.pyc添加如下图所示的8个字节即可修复:


图7 修复pyc文件

修复完成后,将.pyc文件解码成.py文件即可还原完成。

解码可使用uncompyle6工具,也可以在线解码https://tool.lu/pyc/https://python-decompiler.com/en/


图8 解码pyc为py文件

到此为止,已成功还原PyInstaller打包的可执行文件。

0x2 参考

...

Tags Read More..


如何制作一个即插即用的Python环境?

by LauCyun Mar 18,2018 21:26:14 21,147 views

当你在某工厂渗透测试时,你可能需要在工厂的工程师站的电脑上运行Python脚本,但是工程师站的电脑是不能装东西,那怎么办呢?

我的方案是:先绿化Python安装包,然后量产U盘(2个区:CD-ROOM和U盘),再然后把绿色版Python装入U盘的CD-ROOM中,最后通过autotun.inf把U盘中的Python加入到环境变量中。


图1 绿色版Python

这样就不需要手动把U盘中的Python加入到环境变量中,既方便又装逼。

实验环境:

在量产之前,拔下电脑上所有的USB设备,只保留Kingston DT SE9H。

0x01 准备

先下载U盘检测工具ChipGenius,下载地址:http://www.upantool.com/test/xinpian/2011/ChipGenius_V4.html

下载完成后,用ChipGenius检测U盘的芯片型号等信息,检测结果如下图:


图3 U盘的详细信息

只要看图3中的主控厂商、主控型号两个信息,如下:

  • 主控厂商: Phison(群联)
  • 主控型号: PS2251-68(PS2268) - F/W 02.02.55 [2015-06-12]

最后,就是下载量产工具。

http://www.upantool.com/中输入关键字PS2251-68搜索,我选择的量产工具是群联UPTool v2.093版(2015.03.12),下载地址:http://www.upantool.com/liangchan/Phison/2016/8872.html

下载、解压完成后,运行UPTool_Ver2093.exe,如果出现图4,则说明量产工具选对了。


图4 UPTool_Ver2093.exe界面

准备工作完成后,接下来就是量产啦~~~

0x02 制作

先对U盘进行量产设置(也叫生产设定),点击生产设定按钮,提示输入密码,默认密码为空。


图5 量产设置

量产模式有好几个,我们做的是CD-ROOM+U盘(也就是模式21),则需要启用光碟模拟(也就是设置两个区)(如图6所示):

  • 分区1:分区模式选择光驱(只读模式),再选择Python2-Portable.iso写入。
  • 分区2:啥也不用管。


图6 设置量产模式和分区

这样量产分区就OK了,点击确定即可保存且返回主界面,点击开始即可开始量产,如图7所示:


图7 开始量产

开始漫长的等待时间了,也许一根烟、也许两杯茶、也许睡一觉。。。。。


图8 量产完成

经过快2小时后,出现如图8所示,则说明量产完成~

在这里提醒你,一定要关闭UPTool_Ver2093.exe,再插拔U盘。

0x03 测试

拿个新电脑来测试一下自己成果啦~

插入U盘后,CD-ROOM+可移动磁盘就呈现在你的眼前了,如图9所示:


图9 CD-ROOM+可移动磁盘

然后就会自动运行脚本Python2.bat,它主要的作用是把E盘中的Python27 (Python26)文件夹复制到F盘,然后把其加入环境变量PATH,整个过程如图10所示:


图10 自动运行脚本Python2.bat

运行python -V检查是否成功,如图11所示则说明成功:


图11 检查是否成功

这样,就可以使用U盘中的Python环境啦~~~~

0x04 参考

...

Tags Read More..


Python 中 struct 模块的用法

by LauCyun Feb 23,2018 13:52:14 10,889 views

Python 为了保持语言的简洁,仅仅为用户提供了几种简单的数据结构:intfloatstrlistdict 和 tuple。不同于编译型语言 C/C++,在 Python 中,我们往往不需要关心不同类型的变量在解释器内部的实现方式。例如,对于一个长整形数据,我们在 Python 2 中可以直接写成 a=123456789012345L,而不用去考虑变量 a 占了几个字节。这种抽象的方式为程序的编写提供了足够的支持,但是在某些情况下(比如读写二进制文件,进行网络 Raw Socket 编程)的时候,我们需要一些其他模块来实现我们关于变量长度控制的需求。

struct 模块

当我们在 Python 中跟二进制数据打交道的时候,就要用到 struct 这个模块了。struct 模块为 Python 与 C 的混合编程,处理二进制文件以及进行网络协议交互提供了便利。理解这个模块主要需要理解三个函数:

struct.pack(fmt, v1, v2, ...)
struct.unpack(fmt, string)
struct.calcsize(fmt)

第一个函数 pack 负责将不同的变量打包在一起,成为一个字节字符串,即类似于 C 语言中的字节流。第二个函数 unpack 将字节字符串解包成为变量。第三个函数 calsize 计算按照格式 fmt 打包的结果有多少个字节。这里打包格式 fmt 确定了将变量按照什么方式打包成字节流,其包含了一系列的格式字符串。这里就不再给出不同格式字符串的含义了,详细细节可以参照 7.1. struct — Interpret bytes as packed binary data — Python 3.6.4 documentation.

使用 struct 打包定长结构

一般而言,在使用 struct 的时候,要打包的数据都是定长的。定长的数据代表你需要明确给出要打包的或者解包的数据长度,否则打包解包函数将会出错。下面用例子说明什么是定长打包:

import struct

a = struct.pack("2I3sI", 12, 34, b"abc", 56)
print(a)
## 输出 
b'\x0c\x00\x00\x00"\x00\x00\x00abc\x008\x00\x00\x00'

b = struct.unpack("2I3sI", a)
print(b)
## 输出 
(12, 34, b'abc', 56)

我们可以调用 calcsize() 来计算 "2I3sI" 这个模式占用的字节数:上面的代码将两个整数 12 和 34,一个字符串 “abc” 和一个整数 56 一起打包成为一个字节字符流,然后再解包。其中打包格式中明确指出了打包的长度:"2I" 表明起始是两个unsigned int"3s" 表明长度为3的字符串,最后一个 "I" 表示最后紧跟一个 unsigned int。所以上面的打印 b 输出结果是:(12, 34, b'abc', 56)。

print(struct.calcsize("2I3sI"))
## 输出 
16

可以看到上面的三个整型加一个 3 字符的字符串一共占用了 16 个字节。为什么会是 16 个字节呢?不应该是 15 个字节吗?其实,在 struct 的打包过程中,根据特定类型的要求,必须进行字节对齐。由于默认 unsigned int 型占用四个字节,因此要在字符串的位置进行4字节对齐,因此即使是 3 个字符的字符串也要占用 4 个字节。

再看一下不需要字节对齐的模式:

print(struct.calcsize("2Is"))
## 输出 
9

由于单字符出现在两个整型之后,不需要进行字节对齐,所以输出结果是 9.

需要指出的是,对于 unpack 而言,只要 fmt 对应的字节数和字节字符串 string 的字节数一致,就可以成功的进行解析,否则 unpack 函数将抛出异常。例如我们也可以使用如下的 fmt 解析出 a

c = struct.unpack("2I2sI", a)
print(struct.calcsize("2I2sI"))
print(c)

## 输出 
16
(12, 34, b'ab', 56)

可以看到这里 unpack 解析出了字符串的前两个字符,没有产生任何问题。

struct 处理不定长数据

在上一节的介绍中,我们看到了在使用 pack 和 unpack 的过程中,我们需要明确的指出打包模式中每个位置的长度。比如格式 "2I3sI" 就明确指出了整型的个数和字符串的个数。有时候,我们还可能会需要处理变长的打包数据。

变长字符串的打包

例如我们在程序中可能会得到一个字符串 s,这个 s 没有一个固定的长度,所以我们每次打包的时候都需要将 s 的长度也打包到一起,这样我们才能进行正确的解包。其实,这种情况在处理网络数据包中非常常见。在使用网络编程的时候,我们可能利用报文的第一个字段记录报文的长度。每次读取报文的时候,我们先读取报文的第一个字段,获取其长度之后在处理报文内容。

我们可以采用两种方式处理这种情况:

s = bytes(s, 'utf-8')    # Or other appropriate encoding
struct.pack("I%ds" % (len(s),), len(s), s)

或者

struct.pack("I", len(s)) + s

第一种方式先将报文转变成为字节码,然后获取字节码的长度,将长度嵌入到打包之后的报文中去。可以看到格式字符串中的 "I" 就用来记录报文的长度。第二种方式是直接将字符串的长度打包成字节字符串,再跟原始字符串做一个连接操作。

变长字符串的解包

根据上面的打包方式,我们可以轻松的解开打包串:

int_size = struct.calcsize("I")
(i,), data = struct.unpack("I", data[:int_size]), data[int_size:]
data_content = data[i:]

由于报文的长度 len(s) 我们使用定长的整型 "I" 进行了打包,所以解包的时候我们可以先将报文长度获取出来,之后再根据报文长度读取报文内容。

...

Tags Read More..


在Python中用Memcached作缓存

by LauCyun Dec 21,2017 23:04:13 12,791 views

Memcached是一个高性能的分布式内存对象缓存系统,用于动态WEB应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态,数据库网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon)是用C写的,但是客户端可以用任何语言来编程,并通过memcached协议与守护进程通信。如下图所示:


图片来源:互联网

Memcached官网:http://memcached.org

1 安装与运行Memcached

Memcached支持许多平台:Linux、BSD、Mac OS,也可以安装在Windows上。

Linux系统安装Memcached,首先要先安装libevent库。

# Ubuntu/Debia
sudo apt-get install -y libevent libevent-deve
# Redhat/Fedora/Centos
yum install -y libevent libevent-deve

自动安装

Ubuntu/Debian:

sudo apt-get install memcached

Redhat/Fedora/Centos:

yum install memcached

源代码安装

从其官方网站下载Memcached最新版本:

wget -c http://memcached.org/latest  # 下载最新版本
tar -zxvf memcached-1.x.x.tar.gz     # 解压源码
cd memcached-1.x.x                   # 进入目录
./configure                          # 配置
make && make test                    # 编译
sudo make install                    # 安装

运行Memcached

memcached -m 256 -u root -p 11211 -l 127.0.0.1 -c 128 -P /tmp/memcached.pid -d

参数说明:

  • -m:分配给memcached使用的内存数量,单位是MB,默认是64MB;
  • -u:运行memcached的用户;
  • -p:设置memcached监听的端口,最好是1024以上的端口,默认是11211;
  • -l:监听的服务器IP地址,可以有多个地址;
  • -c:选项是最大运行的并发连接数,默认是1024,按照你服务器的负载量来设定;
  • -P:设置保存memcached的pid文件;
  • -d:启动一个守护进程

其他的参数,请通过memcached -h查阅。

可以启动多个守护进程,但是端口不能重复。 设置开机启动的话可以将上行命令增加到/etc/rc.d/rc.local文件中。

再介绍一下,Memcached的命令有:

  • 存储命令:setaddreplaceappendprependcas
  • 查找命令:getgetsdeleteincrdecr
  • 统计命令:statsstats itemsstats slabsstats sizesflush_all

2 Python操作Memcached

网上流传说Python-API中效率最高的是libmc,另外还有python-memcached。不过由于目前需要中效率并没有太高要求,于是选择了使用最多的python-memcached

安装

pip install python-memcached

安装完后,查看一下python-memcached版本:

$ pip list | grep python-memcached
python-memcached (1.59)

先来看一个简单的例子:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

# 连接
mc = memcache.Client(["127.0.0.1:11211"], debug=True)
# 插入
mc.set("hello", "Hello memcached!")
# 读取
ret = mc.get("hello")
print(ret)

运行后,输出结果:

Hello memcached!

其中debug=True表示运行出现错误时,可以显示错误信息,生产环境中可以不加。

集群

python-memcached模块原生支持集群操作,其原理是在内存中维护一个主机列表,且集群中主机的权重值和主机在列表中重复出现的次数成正比。

主机 权重
127.0.0.11:11211 1
192.168.56.1:11212 2
192.168.0.148:11213 3

那么内存中主机列表为host_list = ["127.0.0.1", "192.168.56.1", "192.168.56.1", "192.168.0.148", "192.168.0.148", "192.168.0.148", ]

用户如果要在内存中创建一个键值对(eg. key1 = "value1"),那么要执行以下步骤:

  • 根据算法将key1转换成一个数字
  • 将数字和主机列表长度求余数,得到一个值N(0 <= N < 长度)
  • 在主机列表中根据第二步得到的值为索引获取主机,例如: host_list[N]
  • 连接将第三步中获取的主机,将key1 = "value1"放置在该服务器的内存中

实现代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

# 集群
mc = memcache.Client([('127.0.0.1:11211', 1), ('192.168.56.1:11212', 2), ('192.168.0.148:11213', 3)])
# 插入
mc.set('key1', 'value1')
print(mc.get("key1"))

"""
  验证
"""
# 127.0.0.1:11211
mc1 = memcache.Client(['127.0.0.1:11211'])
print("host=127.0.0.1:11211, ", "key1=", mc1.get("key1"))
# 192.168.56.1:11212
mc2 = memcache.Client(['192.168.56.1:11212'])
print("host=192.168.56.1:11212, ", "key1=", mc2.get("key1"))
# 192.168.0.148:11213
mc3 = memcache.Client(['192.168.0.148:11213'])
print("host=192.168.0.148:11213, ", "key1=", mc3.get("key1"))

运行结果:

value1
host=127.0.0.1:11211,  key1= None
host=192.168.56.1:11212,  key1= None
host=192.168.0.148:11213,  key1= value1

说明键值对key1 = "value1"存在192.168.0.148:11213中。

add

add用于添加一个键值对,如果已经存在的key,重复执行add操作会出现异常。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(["127.0.0.1:11211"], debug=True)
# set
ret1 = mc.add("key-add", "value")
print(ret1)

ret2 = mc.add("key-add", "value")
print(ret2)

运行结果:

True
MemCached: while expecting 'STORED', got unexpected response 'NOT_STORED'
False

replace

replace用于修改某个key的值,如果key不存在,则出现异常。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(["127.0.0.1:11211"], debug=True)
# add
mc.add("key-replace", "value1")
ret1 = mc.get("key-replace")
print(ret1)
# replace
mc.replace("key-replace", "value2")
ret2 = mc.get("key-replace")
print(ret2)

运行结果:

value1
value2

set 和 set_multi、get 和 get_multi

set用于设置一个键值对,如果key不存在,则创建;如果key存在,则修改。

set_multi用于设置多个键值对,如果key不存在,则创建;如果key存在,则修改。

get获取一个键值对。

get_multi获取多个键值对,keys为一个list

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(["127.0.0.1:11211"], debug=True)
# set
mc.set("key-set", "value1")
ret = mc.get("key-set")
print(ret)
# set multi
dic = {"key-set-1": "value1-1", "key-set-2": "value1-2", "key-set-3": "value1-3"}
mc.set_multi(dic)
print(mc.get_multi(['key-set-1', 'key-set-2', 'key-set-3']))

运行结果:

value1
{"key-set-1": "value1-1", "key-set-2": "value1-2", "key-set-3": "value1-3"}

delete 和 delete_multi

delete用于删除指定的一个键值对。

delete_multi用于删除指定多个键值对,貌似现在不能用。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(['127.0.0.1:11211'], debug=True)
# set
mc.set('key-delete', 'value-delete')
print(mc.get('key-delete'))
# # delete
mc.delete('key-delete')
print(mc.get('key-delete'))

# set_multi
dic = {'key-delete-1': 'value1-delete-1', 'key-delete-2': 'value1-2', 'key-delete-3': 'value1-delete-3'}
mc.set_multi(dic)
print(mc.get_multi(['key-delete-1', 'key-delete-2', 'key-delete-3']))
# delete multi
mc.delete_multi(['key-delete-1', 'key-delete-2', 'key-delete-3'])
print(mc.get_multi(['key-delete-1', 'key-delete-2', 'key-delete-3']))

运行结果:

value-delete
None
{'key-delete-2': 'value1-2', 'key-delete-1': 'value1-delete-1', 'key-delete-3': 'value1-delete-3'}
{}

append 和 prepend

append用于修改已存在key的值后面追加内容。

prepend用于修改已存在key的值前面插入内容。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(['127.0.0.1:11211'], debug=True)
# set
mc.set('key1', 'value')
print(mc.get('key1'))
# append
ret1 = mc.append("key1", "-append")
print(ret1)
print(mc.get('key1'))
# prepend
ret2 = mc.prepend("key1", "prepend-")
print(ret2)
print(mc.get('key1'))

运行结果:

value
True
value-append
True
prepend-value-append

incr 和 decr

incr用于对已存在的key的数字值进行自增操作。

decr用于对已存在的key的数字值进行自减操作。

incrdecr 操作的数据必须是十进制的32位无符号整数。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(['127.0.0.1:11211'], debug=True)
# set
mc.set('key1', 10)
print("key1=%s" % mc.get('key1'))
# incr
ret1 = mc.incr("key1", 10)
print(ret1)
print("key1=%s" % mc.get('key1'))
# decr
ret2 = mc.decr("key1", 5)
print(ret2)
print("key1=%s" % mc.get('key1'))

运行结果:

key1=10
20
key1=20
15
key1=15

至于其他的命令就不一一介绍了,想继续了解的话,请阅读http://www.runoob.com/memcached/memcached-tutorial.html

3 参考

...

Tags Read More..


更换pip源到国内镜像

by LauCyun Nov 28,2017 17:46:02 19,539 views

对于默认的pip源的速度实在无法忍受,经常出现错误,于是便搜集了一些国内的pip源,如下:

临时使用

使用方法很简单,直接-iurl即可,如下:

pip install snownlp -i https://pypi.doubanio.com/simple

如果有如下报错:


图1 临时使用douban源错误信息

请使用命令:

pip install snownlp -i https://pypi.doubanio.com/simple --trusted-host pypi.doubanio.com

这样pip就可以指定的镜像源安装python包了。

永久修改

如果想修改默认的镜像源,Linux系统中,需要修改~/.pip/pip.conf

[global]
index-url = http://pypi.doubanio.com/simple

[install]
trusted-host=pypi.doubanio.com

pip.conf中,添加以上内容,就修改了默认的软件源。

如果是windows系统,直接在用户目录中创建一个pip目录c:\Users\xxx\pip,新建文件pip.inipip.ini中,添加以上内容即可。

以后pip命令会直接从制定的软件源安装python包了。


图2 使用douban源安装python包

参考

...

Tags Read More..