zipファイルのパスワード解析ソフトを自作してみた - bogamp’s blog
以前pythonでzipファイルのパスワード解析ソフトを作ったが、今度はc++で作ってみた。
#include <iostream> #include <fstream> #include <stdio.h> #include <zip.h> #include <vector> #include <string> #include <zlib.h> #include <cstring> #include <memory> std::vector<std::string> read_file(std::string filename){//パスワードリストのファイルを読み込む関数 std::string line; std::vector<std::string> content; content.reserve(1000000);//ここは無くても良いが、行数文だけ先に領域確保しておけば少し速くなる std::ifstream passfile(filename); if(passfile.is_open()){ while(getline(passfile,line)){ content.push_back(line); } passfile.close(); } return content; } long calcrc(char data[],int len){//crc32は、zipファイルの誤り検出用の数字。これが一致すればファイル内容が正しいと確認できる。 const void* voidata = data; long res = crc32(0L, NULL, 0); res = crc32(res, static_cast<const Bytef*>(voidata), len);//libzipにはcrc32を計算できる関数は無いようなので、zlibの関数を使う return res; } int main(int argc, char *argv[]){ auto passlist = read_file(argv[2]);//パスワードリストのファイルを読み込む auto archive = zip_open(argv[1],0,NULL);//zipファイルを開く zip_file_t * zfile = NULL; try{ auto passnum = passlist.size(); zip_stat_t stat; zip_stat_init(&stat); zip_stat_index(archive,0,0,&stat);//すべてのファイルのパスワードが同一だと仮定して、ここではindexが0のファイルを対象にする。 auto filesize = stat.size;//ファイルサイズ long filecrc = (long)stat.crc; auto filetext = std::make_unique<char[]>(filesize);//読み込んだファイル内容を格納するためにメモリ確保 for(int i=0;i<passnum;++i){ auto pass = passlist.at(i); zfile = zip_fopen_index_encrypted(archive,0,0,pass.c_str());//openに失敗した場合、エラーを投げるのではなくNULLを返す仕様らしい if(zfile != NULL){ int res = zip_fread(zfile,filetext.get(),filesize);//resには読み込んだ文字列のサイズを返す。よってfilesizeと同じならおそらく成功したと判定できる。 if(res==filesize){ if(filecrc == calcrc(filetext.get(),res)){//crc32を計算してチェック std::cout << "answer : " + pass << std::endl; break; } } zip_fclose(zfile); } } zip_close(archive); }catch(...){ if(zfile != NULL){ zip_fclose(zfile); } zip_close(archive); } }
参考:https://libzip.org/documentation/
libzipとzlibを使っているので、g++でコンパイル時は-lzipと-lzをリンクオプションでつける。
間違ったパスワードのときはzip_fopen_index_encryptedが必ず失敗してくれるなら簡単なのだが、zipの使用上無理らしい(試してみると1%くらいはopenに成功してしまう)ので、ファイル内容を読み込んでチェックする必要がある。
さすがにpythonよりはずいぶん速くなった。
C++初心者なのであんまり自信はないですが、スマートポインタとvectorを使っているので、メモリリークとかは多分ないはず…