>  ×

4,197,000

検索ツール

91 out of 100 based on 1977 user ratings

ミアグループオフィシャル ミアカフェ·ミニ制服 パンプキン M コスプレ 可愛い メイド アリス ウェイトレス アニメ 制服 アイドル アキバ ゴスロリ クラシック エプロン ハロウィン 仮装 大人 コスチューム セクシー 衣装 メイド アリス ウェイトレス アニメ 制服 アイドル ゴスロリ クラシック エプロン イベント ハロウィン 仮装 コスプレ コスチューム 衣装 5000円以上で送料無料 cm0936


2020-02-24
?了承しました。

【10%off送料無料スーパーSALE】コスプレメイドメイド服アリス不思議の国のアリスコスプレ衣装女性コスプレセクシー大人オレンジワンピースパンプキンカラーシャツビスチェエプロンスカートペチコートカチューシリボンコスチューム10%off送料無料スーパーSALE◆ミアグループオフィシャルミアカフェ?ミニ制服パンプキンMコスプレ可愛いメイドアリスウェイトレスアニメ制服アイドルアキバゴスロリクラシックエプロンハロウィン仮装大人コスチュームセクシー衣装10%off?送料無料スーパーSALE◆ミアグループオフィシャルミアカフェ?ミニ制服パンプキンMコスプレ可愛いメイドアリスウェイトレスアニメ制服アイドルアキバゴスロリクラシックエプロンハロウィン仮装大人コスチュームセクシー衣装10%off?送料無料スーパーSALE◆ミアグループオフィシャルミアカフェ?ミニ制服パンプキンMコスプレ可愛いメイドアリスウェイトレスアニメ制服アイドルアキバゴスロリクラシックエプロンハロウィン仮装大人コスチュームセクシー衣装10%off?送料無料スーパーSALE◆ミアグループオフィシャルミアカフェ?ミニ制服パンプキンMコスプレ可愛いメイドアリスウェイトレスアニメ制服アイドルアキバゴスロリクラシックエプロンハロウィン仮装大人コスチュームセクシー衣装
ミアグループオフィシャル ミアカフェ?ミニ制服 パンプキン M ハロウィン






キーワード
コスプレ コスチューム 衣装 メイド ウエイトレス メイド服 ウェイトレス ゴスロリ ロング アキバ
拾い物のコンパス まともに書いたメモ
プログラム実行時の命令数(関数単位)を可視化してみた

ミアグループオフィシャル ミアカフェ·ミニ制服 オンライン パンプキン M コスプレ 可愛い メイド アリス ウェイトレス アニメ 制服 アイドル アキバ ゴスロリ クラシック エプロン ハロウィン 仮装 大人 コスチューム セクシー 衣装:コスプレ通信 メイド アリス ウェイトレス アニメ 制服 アイドル ゴスロリ クラシック エプロン イベント ハロウィン 仮装 コスプレ コスチューム 衣装 5000円以上で送料無料 cm0936

Intel Pin で任意のプログラム実行時の実行命令数を関数単位で計測し, d3.js に食わせたという話.

背景

プログラム解析時に複雑で命令数が多いところはなるだけ読みたくない.
読むなら心構えがしたい.
一目でわかるようにできないかと思って可視化に手を出してみた,第一弾.

処理の流れ
  1. Intel Pinで実行命令数を計測・ CSV で出力(サンプルをほぼ流用できた)
  2. 1.の出力を JSON に変換
  3. d3.jsに食べさせる

まとめてしまうとこれだけ.大したことはしていない.
しかし d3.js が曲者で時間を取られた.

実行環境

お決まりのやつ.

$ uname -aLinux poppycompass 5.3.11-arch1-1 #1 SMP PREEMPT Tue, 12 Nov 2019 22:19:48 +0000 x86_64 GNU/Linux
$ gcc -v(snip)gcc version 9.2.0 (GCC)
Intel Pinで実行命令数の計測

まずは Intel Pin を準備.

$ wget https://software.intel.com/sites/landingpage/pintool/downloads/pin-3.11-97998-g7ecce2dac-gcc-linux.tar.gz    $ tar xvf pin-3.11-97998-g7ecce2dac-gcc-linux.tar.gz    $ cd pin-3.11-97998-g7ecce2dac-gcc-linux.tar.gz    $ cd source/tools/ManualExamples/    $ make all TARGET=intel64    $ ../../../pin -t obj-intel64/inscount0.so -- /bin/ls # inscount0は全体で何命令実行されたかのカウントするプログラム    $ cat insount0.out     Count 650939

カウント数が出ればOK.
関数単位での実行命令数を出力するプログラムを組もうと思いきや, proccount.cpp がまさにそれだった.
流石 インテル 入ってる.
そのままだと目に優しいテキストとして出力されるから, CSV 出力にいじった.
全部を載せると長いからいじった Fini 関数のところのみ抜粋.空白を消して , が入るようにしただけ.

// This function is called when the application exits// It prints the name and count for each procedureVOID Fini(INT32 code, VOID *v){    outFile <<  "Procedure" << ","            <<  "Image" << ","            <<  "Address" << ","            <<  "Calls" << ","            <<  "Instructions" << endl;    for (RTN_COUNT * rc = RtnList; rc; rc = rc->_next)    {        if (rc->_icount > 0)            outFile << rc->_name << ","                    << rc->_image << ","                    << hex << rc->_address << dec <<","                    << rc->_rtnCount << ","                    << rc->_icount << endl;    }}

計測対象は簡単のために Hello World とした.
以下を適当なファイルに保存する.

// hello.c#include <stdio.h>int main(void){    puts("hello");    return 0;}
$ gcc hello.c$ ./a.outhello

これで準備は整った.データを取る.

$ ../../../pin -t obj-intel64/proccount.so -- ./a.outhello$ cat proccount.outProcedure,Image,Address,Calls,Instructions__strlen_avx2,libc.so.6,7fe200f906e0,1,16__strrchr_avx2,libc.so.6,7fe200f90510,1,28_dl_addr,libc.so.6,7fe200f67de0,1,66742__init_misc,libc.so.6,7fe200f2e130,1,25sbrk,libc.so.6,7fe200f25190,2,51(snip)

Intel Pin でやることはここまで.

CSV JSON に変換

可視化で見たいものは実行命令数の大小.
棒グラフでも良かったがここではバブルチャートを使うことにした.
d3.js に食わせるには JSON 形式のほうが都合が良さそうだったから変換する.
スクリプト を書いただけ.

#!/usr/bin/env python# -*- coding: utf-8 -*-# file: csv2json.pyimport jsonimport csvCSV_FILE = "proccount.csv"JSON_FILE = "proccount.json"def all_in_one():    json_contents = {}    children = []    with open(CSV_FILE, 'r') as f:        for row in csv.DictReader(f):            children.append(                    {"name": row["Procedure"],                     "size": row["Instructions"]})    with open(JSON_FILE, 'w') as f:        json_contents["name"] = "execute"        json_contents["children"] = children        json.dump(json_contents, f)def each_image():    json_contents = {}    children = {}    with open(CSV_FILE, 'r') as f:        for row in csv.DictReader(f):            if not row["Image"] in children:                children[row["Image"]] = []            children[row["Image"]].append(                    {"name": row["Procedure"],                     "size": row["Instructions"]})    with open(JSON_FILE, 'w') as f:        for (key,val) in zip(children.keys(), children.values()):            json_contents = {}            json_contents["Image"] = key            json_contents["children"] = val            json.dump(json_contents, f)            f.write('\n')if __name__ == '__main__':    all_in_one()

Intel Pin の出力はどのファイル内にある関数かも記録してある.それぞれを取り出すための関数が each_image ,ファイル関係なくまとめたのが all_in_one

$ python csv2json.py$ cat proccount.json{"name": "execute", "children": [{"name": "__strlen_avx2", "size": "16"}, {"name": "__strrchr_avx2", "size": "28"}, {"name": "_dl_addr", "size": "66742"}, {"name": "__init_misc", "size": "25"}(snip)

データの準備もこれで完了

加工したデータをバブルチャートで表示

バブルチャートのサンプルを取ってきたらほぼそのまま使えた.
以下は index.html

<!DOCTYPE html><html> <head>  <meta charset="utf-8">  <title>D3 v5 hierarchy pack v4/v5</title></head> <body>  <svg width="800" height="600"></svg>  <script src="https://d3js.org/d3.v4.min.js"></script>  <script src="graph.js"></script></body></html>
// graph.jsvar diameter = 960,    format = d3.format(",d"),    color = d3.scaleOrdinal(d3.schemeCategory20c);var bubble = d3.pack()    .size([diameter, diameter])    .padding(1.5);var svg = d3.select("body").append("svg")    .attr("width", diameter)    .attr("height", diameter)    .attr("class", "bubble");d3.json("proccount.json", function(error, data) {  if (error) throw error;  var root = d3.hierarchy(classes(data))      .sum(function(d) { return d.value; })      .sort(function(a, b) { return b.value - a.value; });  bubble(root);  var node = svg.selectAll(".node")      .data(root.children)    .enter().append("g")      .attr("class", "node")      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });  node.append("title")      .text(function(d) { return d.data.className + ": " + format(d.value); });  node.append("circle")      .attr("r", function(d) { return d.r; })      .style("fill", function(d) {         return color(d.data.packageName);       });  node.append("text")      .attr("dy", ".3em")      .style("text-anchor", "middle")      .text(function(d) { return d.data.className.substring(0, d.r / 3); });});// Returns a flattened hierarchy containing all leaf nodes under the root.function classes(root) {  var classes = [];  function recurse(name, node) {    if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });    else classes.push({packageName: name, className: node.name, value: node.size});  }  recurse(null, root);  return {children: classes};}d3.select(self.frameElement).style("height", diameter + "px");

今回はローカルにある proccount.json を読み込むため,通常のブラウザだと CORS 関連で弾かれる.
これはブラウザ起動時にオプションをつければ良い.

$ google-chrome-stable --allow-file-access-from-files --disable-web-security --user-data-dir --disable-features=CrossSiteDocumentBlockingIfIsolating

開いたブラウザから file://パス/index.html へアクセスする.

結果

ミアグループオフィシャル ミアカフェ·ミニ制服 オンライン パンプキン M コスプレ 可愛い メイド アリス ウェイトレス アニメ 制服 アイドル アキバ ゴスロリ クラシック エプロン ハロウィン 仮装 大人 コスチューム セクシー 衣装:コスプレ通信 メイド アリス ウェイトレス アニメ 制服 アイドル ゴスロリ クラシック エプロン イベント ハロウィン 仮装 コスプレ コスチューム 衣装 5000円以上で送料無料 cm0936 メイン処理と全く関係ないところが非常に大きな比重を占めていることがひと目でわかる.
そりゃ main 部なんて printf してるだけだからこの図じゃわかるわけなかった.
これだけだともやもやするからファイル毎の関数で可視化してみた(前述の each_image を利用).
each_image の出力は各ファイル単位で改行されるから,見たいやつ以外の行を消すこと.
以下, libc.so.6 , ld-linux-x86-64.so.2 , a.out の結果.

ミアグループオフィシャル ミアカフェ·ミニ制服 オンライン パンプキン M コスプレ 可愛い メイド アリス ウェイトレス アニメ 制服 アイドル アキバ ゴスロリ クラシック エプロン ハロウィン 仮装 大人 コスチューム セクシー 衣装:コスプレ通信 メイド アリス ウェイトレス アニメ 制服 アイドル ゴスロリ クラシック エプロン イベント ハロウィン 仮装 コスプレ コスチューム 衣装 5000円以上で送料無料 cm0936 ミアグループオフィシャル ミアカフェ·ミニ制服 オンライン パンプキン M コスプレ 可愛い メイド アリス ウェイトレス アニメ 制服 アイドル アキバ ゴスロリ クラシック エプロン ハロウィン 仮装 大人 コスチューム セクシー 衣装:コスプレ通信 メイド アリス ウェイトレス アニメ 制服 アイドル ゴスロリ クラシック エプロン イベント ハロウィン 仮装 コスプレ コスチューム 衣装 5000円以上で送料無料 cm0936 f:id:poppycompass:20191118142101j:plain

バブルの大きさは各ファイルの命令数の平均に影響されている. a.out main は7命令だけど結構大きくなってしまっている.

所感

命令数が多い=重要な関数かと言われると実行準備段階の命令も入っているから一概に言えない.
処理を追う上では流れの関係を示さなければ役には立たなさそうだ.

d3.js ってエクセルの3Dマップのように球体表示し,ドラッグドロップで後ろまで見えるかと思っていたが,そこまでの機能はないようだ.
可視化はあくまでネットワーク図のように繋がりを一目で表現するためのものでCADみたいな3Dツールとは別物なんだと知った.

ごちゃごちゃ書いたが結局これだけだと解析にはイマイチ使えない.
次の方法を考えないといけない.

参考

Intel Pinを使ってみる - ももいろテクノロジー

Bubble Chart d3 v4 - bl.ocks.org

json --- JSON エンコーダおよびデコーダ — Python 3.8.0 ドキュメント

JsonからPythonで複数のキー値を持つ入れ子になったJson構造を作成する - コードログ

yaourtがいつの間にか消えていた話

AUR使うときに世話になっている yaourt がいつの間にか開発終了していて, yay という代替プログラムに乗り換えた.

経緯

3年ぶりくらいに Arch Linux を最初からインストールして環境を構築した.
AURを使うために

$ pacman --sync --refresh yaourt

とかで yaourt をインストールしようとしても見つからない.
なんでだろうと調べていたら開発が終了していた.
日本語の記事が少なかったのと英語の記事タイトルが Yaourt is dead! ( unsupported とかで検索していた)となっていたから調べるのに苦労した.
kill といいやたら物騒な表現が好きな世界だ.

代替プログラム( yay )

yay 以外に pakku aurutils もあるが, 参考サイト が綺麗に書いているからそっちに譲る.
今回は使い勝手が同じそうな yay を使うことにした.
Go言語で書かれているらしい.
以下,導入方法.

yaourt がインストールされているシステム

今使っているやつから乗り換えるときは

$ yaourt -S yay

で簡単にできる.

最初から導入
git clone https://aur.archlinux.org/yay.gitcd yaymakepkg -si
blackarchレポジトリを追加しているとき

流石の品揃え.

$ pacman -Ss yayblackarch/yay 9.0.0-1 (blackarch blackarch-misc)    Yet another yogurt. Pacman wrapper and AUR helper written in go.$ pacman -S yay
使い方

以前と同じ.

検索: $ yay -Ss <package>インストール:$ yay -S <package>

尚,他の代替プログラムも検索・インストールに限って言えばオプションは変わらない.

最後に

今までありがとう, yaourt

参考サイト

Don't Install Yaourt! Use These Alternatives for AUR in Arch Linux

Yaourt is Dead! - General ArchLabs Discussion - ArchLabs Linux

Trizenも良いけどyayも使おう - Qiita

CiscoルータからSCPでIOSを抽出する方法メモ

Cisco のルータから IOS を抜き出すときは, FTP 経由での方法をよく聞く.
そこで FTP を試してみたが,上手く行かない.
デバッグ する気が起きなかったから,SCPで抜き出してみることにした.
コピー先の Windows 上でサーバを立てるのは手間だから,ルータ上で SSH サーバを立てて,SCP接続する.
コマンドメモがうろ覚えだから,上手く行かなかったら訂正してくれると嬉しい.

なにがしたかったか

Cisco 機器から IOS のバイナリファイルを抜き出すと,それを使ってGNS3でネットワーク構成を仮想でいじることができる.
というわけでバイナリが欲しかった.

準備

最初はいつも通りにシリアルコンソールで接続する.
加えて,ルータのLANポートのどれかとPCをLANケーブルで接続しておく.
挿したらPCから Telnet でログインしておく.
OSが Windows なら putty から, putty.zip をダウンロード・適当なところに解凍する.今回はデスクトップに解凍した前提で進めていく.
dir コマンドで一応自分が抜き出そうとしている IOS のバージョンを確認しておいたほうが良い.
GNS3でサポートしていないバージョンの可能性がある.

ルータ側での設定

Cisco ルータから Windows がインストールされた端末にコピーする.
ただ打ち込んでいくだけ.
大きな流れは以下の通り.

  1. IPを割り振る
  2. ユーザを作成
  3. SSH 鍵の作成(今回は1024bit)・有効化
  4. SCPを許可
$ enable$ configure terminal$ interface vlan 1$ ip address 192.168.1.100 255.255.255.0$ username cisco privilege 15 password cisco$ line vty 0 4$ login local$ hostname R1 # ここは適当で良い$ ip domain-name r1.com # ここは適当で良い$ crypto key generate rsa modulus 1024$ ip ssh version 2$ ip ssh time-out 120$ ip ssh authentication-retries 3$ ip scp server enable$ aaa new-model$ aaa session-id unique$ aaa authentication login default local # 認証にローカルDBを利用$ aaa authorization exec default local none # ログイン認可方式として,全ての回線にローカルDBを使用して認可する.$ enable secret cisco

ルータ側の設定はこれで終了.
ポイントは aaa 認証部分.
aaa Authentication/Authorization/Accounting に関する制御コマンド.
認証方式を全てローカルのDBに設定しないと,認証が上手く行かない.

IOS を抜き出す

ルータ側で

$ dir flash

IOS のファイル名を確認する.
Windows でプロンプトを開く.

$ cd C:\Users\Desktop\putty # puttyを解凍したフォルダに移動$ pscp.exe -scp cisco@192.168.1.100:???.bin C:\Users\poppycompass\Desktop\IOS

これでダウンロードできる.
Linux なら scp を打つだけで良い.

失敗談

失敗した事例をメモしておく.

  • SCP: [22 -> 192.168.1.100:?????] send Privilege denied. が出る.

    • 多分,ユーザの権限が十分じゃない. username cisco privilege 15 password cisco などで権限を最高にしていないか( show privilege で確認), aaa を設定していない
  • WinSCP でSCPできない

    • ログインターミナルの関係でエラーが出て上手く行かない. Linux のターミナル使うか, putty CUI ( pscp.exe )を使おう.
  • スイッチで同じ設定してみたが,上手く行かない

    • 原因不明.知りたい.
おまけ

抜き出してから, IOS のバージョンがGNS3のサポート対象外であることに気づいた.
呆然としつつ, file コマンドすると ELF 32-bit MSB executable, Sunplus S+core7 RISC, version 1 (SYSV), statically linked, stripped と出て驚いた.
どうやら IOS の正体はELF形式のプログラムのようだ. Wiki にも碌に情報が載っていない.
これはまたマニアックな アーキテクチャ を使っているな・・・.

OSがELFってことは, BIOS かそれに準ずるプログラムがELFを実行できるということだろうか.
OSを実行するためのOSでも存在するのかな.
謎だけ残ってしまった.

所感

SCPだと ファイアウォール の無効化とかがいらないから,躓きが少なくて良い.

参考

Memo.html[Cisco]IOSイメージの抽出(追記2017/4/3)

Cisco IOS セキュリティ コマンド リファレンス:コマンド D ~ L、Cisco IOS XE Release 3SE(Catalyst 3850 スイッチ) - ip scp server enable [Cisco Catalyst 3850 シリーズ スイッチ] - Cisco

Solved: SCP error - Cisco Community

IOSでSCPを利用する : TEMPEST社長ブログ

AAAとは

メイド アリス ウェイトレス アニメ 制服 アイドル ゴスロリ クラシック エプロン イベント ハロウィン 仮装 コスプレ コスチューム 衣装 5000円以上で送料無料 cm0936。ミアグループオフィシャル ミアカフェ·ミニ制服 パンプキン M コスプレ 可愛い メイド アリス ウェイトレス アニメ 制服 アイドル アキバ ゴスロリ クラシック エプロン ハロウィン 仮装 大人 コスチューム セクシー 衣装
CiscoルータからSCPでIOSを抽出する方法メモ
pycを読む(スクリプト味)

前回 はpycを低レベルな命令に変換して読む方法を説明した.
あれはあれで読めはするが, アセンブリ言語 と同様の読みづらさはある.
今回は直接 pyc python スクリプト まで変換する方法を紹介する.
変換するライブラリは複数あるが,ここでは uncompyle を使った.
結論として,精度はいい感じ.pycにソース保護を期待するのはやめましょう.

uncompyle

python byte-code decompiler.
uncompyle2 uncompyle6 がある.
前者は2系サポート,後者は2・3系両方で使える.

環境 各種バージョン

以下のとおり.

$ uname -a Linux poppycompass 4.18.6-arch1-1-ARCH #1 SMP PREEMPT Wed Sep 5 11:54:09 UTC 2018 x86_64 GNU/Linux$ python2Python 2.7.15 (default, Jun 27 2018, 13:05:28)[GCC 8.1.1 20180531] on linux2

Arch Linux の64ビット版.
つまりただの Linux python は2系.

環境作成
$ virtualenv2 ENV$ . ENV/bin/activate$ pip install uncompyle
サンプル 単純なやつ

適当に組んだ.

# sample.pyimport stringdef add(a, b):    return a+ba = "abc"b = "def"c = "ghi"d = a + b + csum = 0for i in range(100):    sum += 0add(1,2)

pyc を生成して,戻してみる.

$ python2 -m compileall sample.py # pyc生成Compiling sample.py ...$ ENV/bin/uncompyle6 ./sample.pyc # uncompyleで変換# uncompyle6 version 3.2.3# Python bytecode 2.7 (62211)# Decompiled from: Python 2.7.15 (default, Jun 27 2018, 13:05:28)# [GCC 8.1.1 20180531]# Embedded file name: sample.py# Compiled at: 2018-09-26 06:49:02import stringdef add(a, b):    return a + ba = 'abc'b = 'def'c = 'ghi'd = a + b + csum = 0for i in range(100):    sum += 0add(1, 2)# okay decompiling ./sample.pyc

見た感じ,完璧に戻されている.

まともなやつ

簡単なやつだけじゃつまらないから, Oxyry Python Obfuscator から取ってきたNQueensで試してみる.
オリジナルコードは以下.

__all__ = []class NQueens:    """Generate all valid solutions for the n queens puzzle"""        def __init__(self, size):        # Store the puzzle (problem) size and the number of valid solutions        self.__size = size        self.__solutions = 0        self.__solve()    def __solve(self):        """Solve the n queens puzzle and print the number of solutions"""        positions = [-1] * self.__size        self.__put_queen(positions, 0)        print("Found", self.__solutions, "solutions.")    def __put_queen(self, positions, target_row):        """        Try to place a queen on target_row by checking all N possible cases.        If a valid place is found the function calls itself trying to place a queen        on the next row until all N queens are placed on the NxN board.        """        # Base (stop) case - all N rows are occupied        if target_row == self.__size:            self.__show_full_board(positions)            self.__solutions += 1        else:            # For all N columns positions try to place a queen            for column in range(self.__size):                # Reject all invalid positions                if self.__check_place(positions, target_row, column):                    positions[target_row] = column                    self.__put_queen(positions, target_row + 1)    def __check_place(self, positions, ocuppied_rows, column):        """        Check if a given position is under attack from any of        the previously placed queens (check column and diagonal positions)        """        for i in range(ocuppied_rows):            if positions[i] == column or \                positions[i] - i == column - ocuppied_rows or \                positions[i] + i == column + ocuppied_rows:                return False        return True    def __show_full_board(self, positions):        """Show the full NxN board"""        for row in range(self.__size):            line = ""            for column in range(self.__size):                if positions[row] == column:                    line += "Q "                else:                    line += ". "            print(line)        print("\n")    def __show_short_board(self, positions):        """        Show the queens positions on the board in compressed form,        each number represent the occupied column position in the corresponding row.        """        line = ""        for i in range(self.__size):            line += str(positions[i]) + " "        print(line)def main():    """Initialize and solve the n queens puzzle"""    NQueens(8)if __name__ == "__main__":    # execute only if run as a script    main()

戻した結果

__all__ = []class NQueens:    """Generate all valid solutions for the n queens puzzle"""    def __init__(self, size):        self.__size = size        self.__solutions = 0        self.__solve()    def __solve(self):        """Solve the n queens puzzle and print the number of solutions"""        positions = [         -1] * self.__size        self.__put_queen(positions, 0)        print ('Found', self.__solutions, 'solutions.')    def __put_queen(self, positions, target_row):        """        Try to place a queen on target_row by checking all N possible cases.        If a valid place is found the function calls itself trying to place a queen        on the next row until all N queens are placed on the NxN board.        """        if target_row == self.__size:            self.__show_full_board(positions)            self.__solutions += 1        else:            for column in range(self.__size):                if self.__check_place(positions, target_row, column):                    positions[target_row] = column                    self.__put_queen(positions, target_row + 1)    def __check_place(self, positions, ocuppied_rows, column):        """        Check if a given position is under attack from any of        the previously placed queens (check column and diagonal positions)        """        for i in range(ocuppied_rows):            if positions[i] == column or positions[i] - i == column - ocuppied_rows or positions[i] + i == column + ocuppied_rows:                return False        return True    def __show_full_board(self, positions):        """Show the full NxN board"""        for row in range(self.__size):            line = ''            for column in range(self.__size):                if positions[row] == column:                    line += 'Q '                else:                    line += '. '            print line        print '\n'    def __show_short_board(self, positions):        """        Show the queens positions on the board in compressed form,        each number represent the occupied column position in the corresponding row.        """        line = ''        for i in range(self.__size):            line += str(positions[i]) + ' '        print linedef main():    """Initialize and solve the n queens puzzle"""        for i in range(self.__size):            line += str(positions[i]) + ' '        print linedef main():    NQueens(8)if __name__ == '__main__':    main()

やはり,記述はほぼ完璧に戻されている.
面白いのは, """ で付けた コメントアウト は復元でき, # で付けたものは復元できなかったこと.
可読性のためにつける \ も消える.そりゃそんな情報残すわけ無いか.

難読化すると・・・? コスプレ衣装 デュラララ!! DURARARA!! 折原臨也★園原杏里 変装/仮装/豪華/華麗/高品質 コスプレ衣装 デュラララ!! DURARARA!! 折原臨也★もしわからないところがあったら、或いは至急製作の必要がある場合、メールでお問い合わせ下さい。Rubie's アダルト Aquaman コスチューム - M (海外取寄せ品)コスプレ衣装+帽子+道具 2年後 トラファルガー·ロー 変装/仮装/豪華/華麗/高品質 コスプレ トラファルガー·ロー★もしわからないところがあったら、或いは至急製作の必要がある場合、メールでお問い合わせ下さい。Plus サイズ ディープ シー ダイバー 2X (海外取寄せ品)メイン ストリート 24/7 Rey Mysterio ライセンス Youth サイズ フォークス レザー ブラック レプリカ パント (海外取寄せ品) , Lady Laughter 3ピースセット /Roma Costumeローマコスチューム コスプレ衣装 (二次会、結婚式、仮装、パーティー、宴会、ハロウィン) 女性 大人用 仮装コスチューム ハロウィン , ローマ コスチューム ウィッグ with ボウ, ピンク/ホット ピンク, One サイズ (海外取寄せ品)本格 南京玉すだれ 踊り 小道具 (s3252) 玉すだれ 日舞 日本舞踊 舞台 おどり 時代劇 大衆演劇 歌舞伎 大道芸 【お取り寄せ商品】 踊り小道具です。 , 10087 (Womens 12-14) アダルト Finding Dory フィッシュ コスチューム (海外取寄せ品) , 紺と白の清純学園セーラー服(冬服) BIG コスプレ 大きいサイズ 男女兼用 制服 セーラー服 ブレザー 女子高生 学生服 アイドル 余興 女装 男の娘 セクシー 大人 コスチューム キャバ ギャル 衣装 可愛い ハロウィン イベント 仮装 大きいサイズ 男女兼用 制服 セーラー ブレザー セクシー コスチューム ギャル コスプレ 衣装 可愛い ハロウィン イベント 仮装 【5000円以上で送料無料】 cm0192【送料無料】 ホーリーシップ 女性用 S 【 仮装 衣装 コスプレ ハロウィン コスチューム 大人用 女性 女海賊 パーティーグッズ レディース パイレーツ 】 レディース コスプレ衣装 フィクション イベント用品 ハロウィン 仮装 パーティーグッズ ファンタジー 海賊 パイレーツPlus サイズ Workout ビデオ スター コスチューム - 3X (海外取寄せ品) , マリーアントワネット コスプレ ベルサイユ コスチューム マリーアントワネット コスプレ ベルサイユ コスチューム , ミアグループオフィシャル ミアカフェ·ミニ制服 迷彩柄 M コスプレ メイド服 アリス ウェイトレス アイドル アキバ ゴスロリ ロリータ セクシー 大人 コスチューム キャバ ギャル 衣装 可愛い ハロウィン イベント 仮装 メイド アリス ウェイトレス アイドル アキバ ゴスロリ セクシー コスチューム ギャル コスプレ 衣装 可愛い ハロウィン イベント 仮装 【5000円以上で送料無料】 cm0934 , コスチューム ZK-109 三枚カルタ板型鉢金 銅板を三枚に分けた手作り鉢金 【角型せんたくネット 付き】手作りにこだわった鉢金。ジェダイ オビ·ワン·ケノービ 衣装、コスチューム デラックス 大人男性用 スター·ウォーズ 【在庫商品に限り平日13時迄当日発送可】 , チャイルド Rodeo カウボーイ コスチューム Medium (8-10) (海外取寄せ品) , いたずらなネイティブガールコスチューム·フード付きワンピースタイプ 仮装コスチューム コスプレ /ROMAローマコスチューム·仮装·ハロウィン·女性大人用 Romaインポートセクシーコスチューム , ディズニープリンセス グッズ ムーラン ティアラ 冠 王冠 ハロウィン コスプレ コスチューム 衣装 グッズ ディズニー映画 アリバスブラザーズ 【通常便なら送料無料】ムーラン ティアラ ハロウィン コスプレ グッズ , コスプレ衣装+ウィッグ+靴 刀剣乱舞 内番 太鼓鐘貞宗★信濃藤四郎 変装/豪華/華麗/高品質 コスプレ 刀剣乱舞 内番 太鼓鐘貞宗★もしわからないところがあったら、或いは至急製作の必要がある場合、メールでお問い合わせ下さい。リトル ボーイズ Squirrel コスチューム - 18mo (海外取寄せ品)ゴースト フェイス Bleeding マスク コスチューム アクセサリー (海外取寄せ品)ルネサンス メイデン コスチューム - ラージ - ドレス サイズ 10-14 (海外取寄せ品) , DENIX デニックス 4198 バルバロッサ海賊サーベル ゴールド トルコ 16世紀 95cm インテリアやコスプレのアイテムとしても人気です!【送料無料】M,XLサイズあり·ラフィーネメイド服-和-(5色)【数量限定!】 可愛いメイド服と言えばキャンディフルーツ!大きいサイズもご用意してます。 , コスプレ衣装 うたの☆プリンスさまっ· マジLOVEレジェンドスター 神宮寺 レン★来栖翔 変装/仮装/豪華/華麗/高品質 コスプレ衣装 うたの☆プリンスさまっ· マジLOVEレジェンドスター 神宮寺レン★もしわからないところがあったら、或いは至急製作の必要がある場合、メールでお問い合わせ下さい。ティンカー ベル コスプレ 衣装 コスチューム 仮装 ハロウィン ディズニー 大人 ピーターパン Tinker Bell ティンカー ベル コスプレ 衣装 コスチューム 仮装 ハロウィン ディズニー 大人 ピーターパン Tinker Bell , チャイルド フレーム Rabbit コスチューム (海外取寄せ品) , ファンワールド メンズ ゾンビ ドクター, Light グリーン, One サイズ コスチューム (海外取寄せ品)

さっきのやつを Oxyry Python Obfuscator で難読化した結果も試してみる.

""#line:4__all__ =[]#line:6class O0000OO0000OOO0OO :#line:8    ""#line:9    def __init__ (O00OO0O0O0O00OO00 ,O00OO0OO00OOO00OO ):#line:11        O00OO0O0O0O00OO00 .__OO00OO0OO00OOO00O =O00OO0OO00OOO00OO #line:13        O00OO0O0O0O00OO00 .__O00OOO00O0O000000 =0 #line:14        O00OO0O0O0O00OO00 .__O0OO00000O0O0O0O0 ()#line:15    def __O0OO00000O0O0O0O0 (OOOOO0O00OO0O0O0O ):#line:17        ""#line:18        O0OO0000OO0OO0000 =[-1 ]*OOOOO0O00OO0O0O0O .__OO00OO0OO00OOO00O #line:19        OOOOO0O00OO0O0O0O .__OO0OOOO0000O0O00O (O0OO0000OO0OO0000 ,0 )#line:20        print ("Found",OOOOO0O00OO0O0O0O .__O00OOO00O0O000000 ,"solutions.")#line:21    def __OO0OOOO0000O0O00O (O0OO00O0000O000O0 ,O0OOOOO0OOOOO000O ,OO0OOOO00OO00OOO0 ):#line:23        ""#line:28        if OO0OOOO00OO00OOO0 ==O0OO00O0000O000O0 .__OO00OO0OO00OOO00O :#line:30            O0OO00O0000O000O0 .__OOO0OO0O0000O00OO (O0OOOOO0OOOOO000O )#line:31            O0OO00O0000O000O0 .__O00OOO00O0O000000 +=1 #line:32        else :#line:33            for OO000O0OOOOO0O0OO in range (O0OO00O0000O000O0 .__OO00OO0OO00OOO00O ):#line:35                if O0OO00O0000O000O0 .__O00O0O00000O0O00O (O0OOOOO0OOOOO000O ,OO0OOOO00OO00OOO0 ,OO000O0OOOOO0O0OO ):#line:37                    O0OOOOO0OOOOO000O [OO0OOOO00OO00OOO0 ]=OO000O0OOOOO0O0OO #line:38                    O0OO00O0000O000O0 .__OO0OOOO0000O0O00O (O0OOOOO0OOOOO000O ,OO0OOOO00OO00OOO0 +1 )#line:39    def __O00O0O00000O0O00O (OO0OOO0OOO0O0OO0O ,O00000O0O00OOOOOO ,O00O0O000000OOOOO ,OOOO00OOO000OO0OO ):#line:42        ""#line:46        for OOO000O0OO0O00000 in range (O00O0O000000OOOOO ):#line:47            if O00000O0O00OOOOOO [OOO000O0OO0O00000 ]==OOOO00OOO000OO0OO or O00000O0O00OOOOOO [OOO000O0OO0O00000 ]-OOO000O0OO0O00000 ==OOOO00OOO000OO0OO -O00O0O000000OOOOO or O00000O0O00OOOOOO [OOO000O0OO0O00000 ]+OOO000O0OO0O00000 ==OOOO00OOO000OO0OO +O00O0O000000OOOOO :#line:50                return False #line:52        return True #line:53    def __OOO0OO0O0000O00OO (OOOO0OOO0OOO0OO00 ,OO0OO0O00OOO00OO0 ):#line:55        ""#line:56        for O0OOO0O0O0OO00O0O in range (OOOO0OOO0OOO0OO00 .__OO00OO0OO00OOO00O ):#line:57            OOO00OO0OOOOOOOOO =""#line:58            for OO00O0O0OOO0O0000 in range (OOOO0OOO0OOO0OO00 .__OO00OO0OO00OOO00O ):#line:59                if OO0OO0O00OOO00OO0 [O0OOO0O0O0OO00O0O ]==OO00O0O0OOO0O0000 :#line:60                    OOO00OO0OOOOOOOOO +="Q "#line:61                else :#line:62                    OOO00OO0OOOOOOOOO +=". "#line:63            print (OOO00OO0OOOOOOOOO )#line:64        print ("\n")#line:65    def __OO0O00O0O0OOO0OOO (OO0OO000O00O0OO00 ,O00O00O00OO0O0OOO ):#line:67        ""#line:71        OOO000OOO00OO0OOO =""#line:72        for O00OOO000OO0O00OO in range (OO0OO000O00O0OO00 .__OO00OO0OO00OOO00O ):#line:73            OOO000OOO00OO0OOO +=str (O00O00O00OO0O0OOO [O00OOO000OO0O00OO ])+" "#line:74        print (OOO000OOO00OO0OOO )#line:75def OOO0O0OO0OOO000OO ():#line:77    ""#line:78    O0000OO0000OOO0OO (8 )#line:79if __name__ =="__main__":#line:81    OOO0O0OO0OOO000OO ()#line:83

戻す

__all__ = []class O0000OO0000OOO0OO:    """"""    def __init__(O00OO0O0O0O00OO00, O00OO0OO00OOO00OO):        O00OO0O0O0O00OO00.__OO00OO0OO00OOO00O = O00OO0OO00OOO00OO        O00OO0O0O0O00OO00.__O00OOO00O0O000000 = 0        O00OO0O0O0O00OO00.__O0OO00000O0O0O0O0()    def __O0OO00000O0O0O0O0(OOOOO0O00OO0O0O0O):        """"""        O0OO0000OO0OO0000 = [         -1] * OOOOO0O00OO0O0O0O.__OO00OO0OO00OOO00O        OOOOO0O00OO0O0O0O.__OO0OOOO0000O0O00O(O0OO0000OO0OO0000, 0)        print ('Found', OOOOO0O00OO0O0O0O.__O00OOO00O0O000000, 'solutions.')    def __OO0OOOO0000O0O00O(O0OO00O0000O000O0, O0OOOOO0OOOOO000O, OO0OOOO00OO00OOO0):        """"""        if OO0OOOO00OO00OOO0 == O0OO00O0000O000O0.__OO00OO0OO00OOO00O:            O0OO00O0000O000O0.__OOO0OO0O0000O00OO(O0OOOOO0OOOOO000O)            O0OO00O0000O000O0.__O00OOO00O0O000000 += 1        else:            for OO000O0OOOOO0O0OO in range(O0OO00O0000O000O0.__OO00OO0OO00OOO00O):                if O0OO00O0000O000O0.__O00O0O00000O0O00O(O0OOOOO0OOOOO000O, OO0OOOO00OO00OOO0, OO000O0OOOOO0O0OO):                    O0OOOOO0OOOOO000O[OO0OOOO00OO00OOO0] = OO000O0OOOOO0O0OO                    O0OO00O0000O000O0.__OO0OOOO0000O0O00O(O0OOOOO0OOOOO000O, OO0OOOO00OO00OOO0 + 1)    def __O00O0O00000O0O00O(OO0OOO0OOO0O0OO0O, O00000O0O00OOOOOO, O00O0O000000OOOOO, OOOO00OOO000OO0OO):        """"""        for OOO000O0OO0O00000 in range(O00O0O000000OOOOO):            if O00000O0O00OOOOOO[OOO000O0OO0O00000] == OOOO00OOO000OO0OO or O00000O0O00OOOOOO[OOO000O0OO0O00000] - OOO000O0OO0O00000 ==OOOO00OOO000OO0OO - O00O0O000000OOOOO or O00000O0O00OOOOOO[OOO000O0OO0O00000] + OOO000O0OO0O00000 == OOOO00OOO000OO0OO + O00O0O000000OOOOO:                return False        return True    def __OOO0OO0O0000O00OO(OOOO0OOO0OOO0OO00, OO0OO0O00OOO00OO0):        """"""        for O0OOO0O0O0OO00O0O in range(OOOO0OOO0OOO0OO00.__OO00OO0OO00OOO00O):            OOO00OO0OOOOOOOOO = ''            for OO00O0O0OOO0O0000 in range(OOOO0OOO0OOO0OO00.__OO00OO0OO00OOO00O):                if OO0OO0O00OOO00OO0[O0OOO0O0O0OO00O0O] == OO00O0O0OOO0O0000:                    OOO00OO0OOOOOOOOO += 'Q '                else:                    OOO00OO0OOOOOOOOO += '. '            print OOO00OO0OOOOOOOOO        print '\n'    def __OO0O00O0O0OOO0OOO(OO0OO000O00O0OO00, O00O00O00OO0O0OOO):        """"""        OOO000OOO00OO0OOO = ''        for O00OOO000OO0O00OO in range(OO0OO000O00O0OO00.__OO00OO0OO00OOO00O):            OOO000OOO00OO0OOO += str(O00O00O00OO0O0OOO[O00OOO000OO0O00OO]) + ' '        print OOO000OOO00OO0OOOdef OOO0O0OO0OOO000OO():    """"""def OOO0O0OO0OOO000OO():    """"""    O0000OO0000OOO0OO(8)if __name__ == '__main__':    OOO0O0OO0OOO000OO()

まあ,やっぱりしっかりと戻された.

おわりに

python のソース保護としてpycで配布するのが良いという意見があるが, バイトコード にするだけではほぼ無意味なようだ.
本気で保護したいのなら,難読化,言語を変える, クラウド として提供して一切ソースが手元に渡らないようにするくらいだろうか.

今回紹介した uncompyle 以外にも, unpyclib というものもあるようだ.
試してみたらエラーが出て上手く行かなかったから,こちらはまた今度.

リバースエンジニアリング 対策にpycをstripする方法はあるのだろうか?

参考

python - Is it possible to decompile a compiled .pyc file into a .py file? - Stack Overflow

GitHub - wibiti/uncompyle2: Python 2.7 decompiler

uncompyle6 · PyPI

Oxyry Python Obfuscator - The most reliable python obfuscator in the world

どうやったらPythonアプリのソースコードを保護できますか? - Quora

Oxyry Python Obfuscator - The most reliable python obfuscator in the world

pycを読む(アセンブリ味)

pycファイルだけが手元にあり,なにが書いてあるか読みたいときがある.
pycの バイトコード は逆 アセンブル して読める.
やり方と例文をまとめる.
ただし,これは低レベルな命令になるから可読性は良くない.
直接 python コードにまで戻す方法があるから, そっち を使ったほうが良い.
厳密な仕様までは調べてないから,間違いはあるかも.指摘歓迎.

環境 各種バージョン

以下のとおり.

$ uname -a Linux poppycompass 4.18.6-arch1-1-ARCH #1 SMP PREEMPT Wed Sep 5 11:54:09 UTC 2018 x86_64 GNU/Linux$ python2Python 2.7.15 (default, Jun 27 2018, 13:05:28)[GCC 8.1.1 20180531] on linux2

Arch Linux の64ビット版.
つまりただの Linux python は2系.

環境作成

環境はローカルに作成した.

$ virtualenv2 ENV$ . ENV/bin/activate$ pip install dis
pycを逆 アセンブル する スクリプト

以下の スクリプト で変換できる.

# pyc_disasm.pyimport dis, marshalcode = open("sample.pyc", "rb").read()[8:]code = marshal.loads(code)dis.dis(code)

ここでは, sample.pyc というファイルを逆 アセンブル する.
sample.py に変換したいコードを書けばよい.使い方は簡単.

$ python2 -m compileall sample.py # pyc生成$ python2 ./pyc_disasm.py
変換一覧

アセンブル したものは アセンブリ 味になっている.
python による記述と逆 アセンブル したものの比較をいくつか挙げておく.各命令の左にある数値はアドレスのようだ.

ライブラリのインポート 普通にインポート

before

import random

after

0 LOAD_CONST               0 (-1)    3 LOAD_CONST               1 (None)    6 IMPORT_NAME              0 (random)    9 STORE_NAME               0 (random)
ちょっと書き方を変えたインポート

before

from random import *

after

0 LOAD_CONST               0 (-1)    3 LOAD_CONST               1 (('*',))    6 IMPORT_NAME              0 (random)    9 IMPORT_STAR
変数定義

before

a = ''

after

0 LOAD_CONST               0 ('')        3 STORE_NAME               0 (a)
関数呼び出し

before

def hoge(a,b):     return a+bhoge(1,2)

after
最初の部分が関数定義,後半が呼び出したときの部分.
関数呼び出しは,関数名・引数・CALL・戻り値格納先の順になる

0 LOAD_CONST               0 (<code object hoge at 0x7fc3dec66b30, file "./sample.py", line 1>)    3 MAKE_FUNCTION            0    6 STORE_NAME               0 (hoge)    9 LOAD_NAME                0 (hoge)   12 LOAD_CONST               1 (1)   15 LOAD_CONST               2 (2)   18 CALL_FUNCTION            2   21 POP_TOP   22 LOAD_CONST               3 (None)   25 RETURN_VALUE
演算

before
正規輸入品 Earthworks SR40mp ハイレゾ コンデンサーマイク Sound Reinforcement Series SR40 , パナソニック 分電盤 地震かみなりあんしんばん あんしん機能付 リミッタースペース付 露出·半埋込両用形 BHN36362ZR , Panasonic 充電インパクトドライバー 14.4V 5.0Ah グレー EZ75A7LJ2F-H , 漆遊館 歳時記 【G4061-04】 ホワイトマリン 杵形小吸椀 5個セット 化粧箱 φ8.8×8.9cm , その他 消臭&防ダニ ラグマット/絨毯 【190cm×190cm グレー】 正方形 日本製 スミノエ 『カラープランツ』 〔リビング〕【】 ds-1876599 【送料無料】消臭&防ダニ ラグマット/絨毯 【190cm×190cm グレー】 正方形 日本製 スミノエ 『カラープランツ』 〔リビング〕【】 (ds1876599)YKK ap 躯体式バルコニー屋根 ヴェクター 柱奥行移動タイプ 2間×6尺 フラット型 ポリカ屋根 関東間(張り出しあり) 1500N/m2 2·3階バルコニー専用 送料無料【YKKAP】積雪50cm対応 2階設置専用ヴェクターMTB フリーライド·ダウンヒル インテンス 55-EVP 2006 【横浜関内店】 モデルは古いですが、最高コンポのXTRが組み込まれているMTBです! , 伝票関連 マイナンバー収集用台紙(国民年金第3号被保険者委任状付) A4 MNGB003 1パック(100シート) 【洗顔用泡立てネット 付き】本人·配偶者のマイナンバーをまとめて収集!テレビ台 120 テレビボード ブラウン テレビボード ローボード 大川家具 AVボード 大川格安家具 【送料無料】 北欧 低いタイプ テレビボード テレビ台 ロー ローボード うずくり TV台 無垢材 ローテレビボード 日本製 TVボード 和 モダン 和風 国産 完成品 大川家具セントラル マイレター卓上タイプ A4 T-1001NG 浅10【smtb-f】【まとめ買い10個セット品】 ナチュリアテーブル W150×D80×H80cm ホワイト 【ECJ】19インチ 8.0J 5H P.C.D:114.3 INSET:35/38/43/48 共豊 モデラートブレイザー ブラックフィニッシュ(2本セット) , シグマー技研 ギヤモータ SG-SML2-08-120 , ヴィンテージ メタル カニ目 老眼風 ESTETICA 3051-2 現品限り 蔵出し!現品特価!メガネフレーム!モダン柄ウィルトン織カーペット/ラグマット 【パーソナル 170cm×170cm/ベージュ】 正方形 〔リビング ダイニング 玄関 寝室〕 ブロック柄がモダンでおしゃれな絨毯 フロアマットモダン ウィルトン織 ラグマット らぐまっと ラグ らぐ マット まっと ラグまっと らぐマット ラグカーペット , 【XLX800KHWJ LA9】パナソニック 110形 直付型 反射笠付型 省エネタイプ 直管形蛍光灯FLR110形2灯器具相当(節電) 10000 lmタイプ 調光 Ra83 【Panasonic】 【25000円(税込)以上で送料無料/送料込】サマータイヤホイールセット 225/35R20 RAYS レイズ HOMURA 2×9 スパークプレーテッドシルバー/リムエッジDMC 送料無料【期間限定!最安値に挑戦SALE!送料無料!】パスナチュラМ 3年間盗難補償 ヤマハ PAS ナチュラM 3段変速付 YAMAHA 電動アシスト自転車 電動自転車 26インチ PA26NM 6.2Ah【ナチュラ エム М! 防犯登録別】 自転車は完全組立·整備済み発送!オプション取付無料![RT64JH7S-CL-13A]【都市ガス 大バーナー左】 リンナイ ガステーブル ガスコンロ 2口 ワンピーストップ 無水片面焼グリル 幅60cm フラット&クリーン クリスタルコート天板:クリームベージュ 【送料無料】 一人暮らし ガステーブル リンナイ 交換 取り付け 取替えはおまかせ!取付工事で更にポイントゲット ガスコンロ テーブルコンロ , カザール CAZAL サングラス メガネ 眼鏡 めがね メンズ 男性 Mens 人気 ランキング オススメ 送料無料●クスコ / CUSCO●スープラ GA70 (90.8~93.5)MT/AT LSD リア 標準デフ:トルセン Type RS 1.5WAY(1.5&2WAY) , 【送料無料】【Mizuno ミズノ】【防具】野球 キャッチャー用プロテクター <ミズノプロ>(革·ゴムソフト/硬式用)プロテクター 1DJPS11046 ネイビー×レッド【正規品·送料無料】イヴサンローラン ルージュヴォリュプテシャイン 58オレンジターンオン+お肌ツルツルセット【送料無料】オーダーカーテン▼ソフトウェーブ縫製オーバーサイズ対応(下部3ッ巻仕様)2倍ヒダ片開き【幅66~130×高さ381~400cm】川島織物セルコン FELTAシリーズ FT6180~6181 FELTA フェルタ 川島織物セルコンの高級·高品質オーダーカーテン リーズナブル お買い得 激安チェスト フレンチアンティーク調 おしゃれ クラシック家具シ , 用 NSS-600【き】【ポータブルステージ】【会議室】【宴会場】【ホール備品】 (EBM-17-2032-07-001) , Isabel Marant toile Crisi Ankle Boots Isabel Marant toile Crisi Ankle Bootsカードでポイント最大23倍 3/16(土)10:00~3/19(火)1:59迄 KENDA ケンダ KUAVELA SL KR32 サマータイヤ 205/55R16 MKW MK-66 ミルドサティンブラック ホイールセット 4本 16インチ 16 X 7 +42 5穴 114.3 IS250 オーリス カローラルミオン リーフ , クラッツィオ シートカバー ニッサン セレナ H22/12~H24/7 C26/FC26/NC26/FNC26 クラッツィオ エアー EN-0574 clazzio クラッチオ クラッツィオ clazzio シートカバー クラッツィオ エアー クラッチオ セレナ C26/FC26/NC26/FNC26 EN-0574【30%OFF!】【全品送料無料!】LA VACCHETTA GRASSA ラ ヴァケッタ グラッサ ZIP長財布 ガルーシャ 【_包装】【_メッセ入力】【smtb-TK】 2以上の変数による演算.

d = a + b + c

after
a , b , c には,文字列と数値のどちらをいれてもコード自体は変わらない.
直前の LOAD_NAME で入れる値が変わるだけ.
BINARY_ADD は相手が文字列だと連結,数値だと数値演算を行う.
3つの変数が相手だと,2回 BINARY_ADD する.
以下のコードは数値版.

18 LOAD_NAME                0 (a)        21 LOAD_NAME                1 (b)        24 BINARY_ADD        25 LOAD_NAME                2 (c)        28 BINARY_ADD        29 STORE_NAME               3 (d)        32 LOAD_CONST               1 (None)        35 RETURN_VALUE

文字列連結だと以下の通り
before

allchar = string.ascii_letters + string.punctuation + string.digits # import string後

after

80 LOAD_NAME                0 (string)        83 LOAD_ATTR                9 (ascii_letters)        86 LOAD_NAME                0 (string)        89 LOAD_ATTR               10 (punctuation)        92 BINARY_ADD                  93 LOAD_NAME                0 (string)        96 LOAD_ATTR               11 (digits)        99 BINARY_ADD                 100 STORE_NAME              12 (allchar)
ループ

before

sum = 0for i in range(100):    sum += i

after FOR_ITER にジャンプしてループを回しているようだ.

0 LOAD_CONST               0 (0)       3 STORE_NAME               0 (sum)       6 SETUP_LOOP              30 (to 39)       9 LOAD_NAME                1 (range)      12 LOAD_CONST               1 (100)      15 CALL_FUNCTION            1      18 GET_ITER >>   19 FOR_ITER                16 (to 38)      22 STORE_NAME               2 (i)      25 LOAD_NAME                0 (sum)      28 LOAD_NAME                2 (i)      31 INPLACE_ADD      32 STORE_NAME               0 (sum)      35 JUMP_ABSOLUTE           19 >>   38 POP_BLOCK >>   39 LOAD_CONST               2 (None)      42 RETURN_VALUE
ありがちなコード

before
とあるCTF問題にあった一文.

password = ('').join((choice(allchar) for a in range(randint(60, 60))))

after
繰り返し部は GET_ITER が入るようだ.

103 LOAD_CONST               6 ('')    106 LOAD_ATTR               13 (join)    109 LOAD_CONST               7 (<code object <genexpr> at 0x7f2fb42d9330, file "ransomware.py", line 11>)    112 MAKE_FUNCTION            0    115 LOAD_NAME               14 (range)    118 LOAD_NAME               15 (randint)    121 LOAD_CONST               8 (60)    124 LOAD_CONST               8 (60)    127 CALL_FUNCTION            2    130 CALL_FUNCTION            1    133 GET_ITER                134 CALL_FUNCTION            1    137 CALL_FUNCTION            1    140 STORE_NAME              16 (password)
おわりに

正直,いざpyc読むときにはこんな低レベルなやつを読むのは労力が要る.正にドM.
python コードに直に変換する方法がある.
そっち を使ったほうが余程楽.

参考

pycファイルの逆アセンブル - one day in summer

.pycファイルを作成する方法メモ - かせきのうさぎさん

volatilityにSANSのプラグインを追加する方法

volatilityでmimikatzを使いたくなった.
セットアップ方法が見つからなかったから書き残す.

mimikatzとは

Windows のパスワードなどの各種認証情報をメモリから抜き出すツール.
管理者権限の取得やなりすましにも使える.
CTFではメモリダンプからアカウントの平文パスワードを抜き出すのによく使う.
デフォルトではvolatilityと連携して使うことができない.
SANSが プラグイン を書いて公開しているから,それを追加してやれば良い.

やり方

基本は プラグイン をコピーするだけ.

$ git clone https://github.com/volatilityfoundation/volati$ git clone https://github.com/sans-dfir/sift-files       $ cp sift-files/volatility/* volatility/volatility/plugins

これで mimikatz コマンド自体は使えるよう.しかし・・・

$ python2 volatility/vol.py -f ./memdump.mem mimikatzVolatility Foundation Volatility Framework 2.6*** Failed to import volatility.plugins.openioc_scan (ImportError: No module named ioc_writer)ERROR   : volatility.debug    : You must specify something to do (try -h)

python モジュール不足でまだ動かない.
ERROR : volatility.debug : You must specify something to do (try -h) はコマンドが無いときにも出る.わかりにくい.
モジュールについては virtualenv2 でローカル環境を作成して,整えていく.

$ virtualenv2 ENV && . ENV/bin/activate$ pip install distorm3 pycrypto lxml ioc_writer colorama construct==2.5.5-reupload

Crypt.Hash モジュールのために pycrypto AttributeError: 'module' object has no attribute 'ULInt32' construct==2.5.5-reupload で対処.

$ python2 volatility/vol.py -f <mem file> --profile=WinXPSP2x86 mimikatz

これで動く.

参考

error in attribute with construct module · Issue #15 · volatilityfoundation/community · GitHub

python - ImportError: No module named Crypto.Cipher - Stack Overflow

lsass.exe のダンプからユーザーパスワードを抽出 :mimikatz

https://www.iij.ad.jp/dev/tech/techweek/pdf/171108_02.pdf

GitHub - gentilkiwi/mimikatz: A little tool to play with Windows security

Linux系のバックアップ方法メモ

Linux が動いているサーバのバックアップを取ろうとした時に考えたことのメモ.
差分とか定期的バックアップとかいった頭の良いことは他に書いてあるから,取り扱わない.サクッとできるやつだけ.あくまでメモだから,詳しい方法とかは割愛する.

状況

そのうちバックアップを取ろうと思っていた Linux がある日突然壊れた.
幸いハードの故障だったからデータは無事だったが,今後を考えて一度バックアップを作ったほうが良いなと思った.

方法

cron で定期的に取ったり,差分だけ取ったりとか色々あるみたいだが,難しいことを考えなければ以下の3つくらいか.

フルバック アップ

物理的な記憶装置に書いてあるデータを全部丸々コピー.
一番確実にデータを取得できる上に,複数 パーティション ・未使用領域といったデータも一緒に保存できるから,この時点で消してしまっているファイルとかも復旧できるのが強み.
おまけにそのままOSも起動できる( デュアルブート も).
欠点は1TBのバックアップには1TBの記憶装置が必要になること.例え9GBしか使っていなくても,問答無用で1TB必要.
安全にコストはつきものである.
具体的な方法としては dd コマンドかな.
$ dd if=/dev/sda of=backup bs=32M

ファイルシステム ごとバックアップ

使っている領域だけをコピーする.
9GBの Linux なら9GBだけの容量で済む. フルバック アップで悩ましかった問題を解決できる.
当然,未使用領域は保存されないから注意は必要.
フルバック アップの次に検討すると良さそう.

今回調べるまで知らなかったが, Ubuntu ext シリーズで, CentOS XFS ファイルシステム が違う.
だから,使うツールも前者は $ e2image -ra -p /dev/sda1 /dev/sdb1 で後者は $ xfsdump -l0 - /dev/sda1 ./backup.fs みたいになる.
CentOS は古いやつだと xfsdump ではなく, xfs_copy になるようだ.
自分のディストリに合ったやつを選ぶこと.

必要なやつだけまとめる

重要なファイルや ディレクト リのみを保存する.
最も簡単かつ玄人向け.
一番容量が小さくなりやすい.
しかし,必要なファイルがわかる人でないと後で困る.
やり方は zip/tar/cp なりで頑張る感じ.
厄介なことに, $ cp -r / /tmp/backup とかやると特殊ファイル関係でエラーが出て時間を溶かすこともある.
シンプルな手法だからといって,作業量も少なくはいかないようだ( 経験談 ).
/etc, /usr, /var, /home, /root を中心に見ると良さそう.

おわり

とりあえず ファイルシステム のバックアップを取ろうかな.

参考

ディスクのクローン - ArchWiki

Obtain file system information | Linux

6.9. ext4 から XFS への移行 - Red Hat Customer Portal

Linux系のバックアップ方法メモ
スターをつけました

引用をストックしました

引用するにはまずログインしてください

引用をストックできませんでした。再度お試しください

限定公開記事のため引用できません。

読者です 読者をやめる 読者になる 読者になる