13 เม.ย. 2559

Docker private registry with Portus+Enable SSL(Self sign)

//bash command
#git clone https://github.com/SUSE/Portus.git
#cd Portus
#./compose-setup.sh

ทำตาม Configuring-the-registry โดยเฉพาะ USE SSL -> Skip Remote Checks
//ดู สถานะ container
#docker ps

ให้สนใจที่ docker name registry
*จะสนใจ เฉพาะ Docker ID 16b8f518ca08
จากนั้น หา mount volume ของ container ตัวนี้
//หา Mount point ของ 16b8f518ca08
#docker inspect -f {{.Mounts}} 16b8f518ca08

ได้จุด mount ที่ไป /var/lib/registry  ใน container
/var/lib/docker/volumes/<volumeID>/_data /var/lib/registry
//เข้าไปใน directory
#cd /var/lib/docker/volumes/<volumeID>/_data

สร้าง X.509: Private / Public Key
#openssl genrsa -out privatekey.pem 2048
//CN ให้ตรงกับ Domain ที่ตรงกับ ตอน config registry เช่น abc.def.com:5000
#openssl req -new -x509 -key privatekey.pem -out publickey.cer -days 365
#openssl pkcs12 -export -out public_privatekey.pfx -inkey privatekey.pem -in publickey.cer
จะมีไฟล์ privatekey.pem,publickey.cer อยู่ใน /var/lib/docker/volumes/<volumeID>/_data  เครื่อง host
และ อยู่ใน /var/lib/registry ของ container ID 16b8f518ca08 

ต่อไป แก้ไฟล์ confix.ymp ของ registry กลับไปที่ Path ที่ clone git มา เช่น /home/test/Portus/ ให้เข้าไปที่ /home/test/Portus/compose/registry
#vi config.yml
//เพิ่ม
addr: 0.0.0.0:5000
  tls:
    certificate: /var/lib/registry/publickey.cer
    key: /var/lib/registry/privatekey.pem

*/var/lib/registry/ คือ path ที่อยู่ใน container ที่ mount ไปจาก /var/lib/docker/volumes/<volumeID>/_data

Copy public cert ให้ docker client
#mkdir /etc/docker/certs.d
#mkdir /etc/docker/certs.d/abc.def.com:5000
#cp /var/lib/docker/volumes/<volumeID>/_data/publickey.cer /etc/docker/certs.d/abc.def.com:5000/ca.crt

Restart Container 16b8f518ca08 
#docker restart 16b8f518ca08

ลอง Login
#docker login -u caznova -e mail@mail.com abc.def.com:5000
//Login Succeeded

31 มี.ค. 2559

Visual C++ for Linux Development V.1.0 ได้ยังงัยนะ


Error อันแรกคือ
"Failed to determine the effective user, could not retrieve the effective user id"

ทั้งใน centos 6.5 กะ ubuntu 14.04 x64

มีสอง Dll อยู่ใน
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Application Type\Linux\1.0
คือ libraspberry.dll กับ Microsoft.Build.Raspberry.Tasks.dll


ไล่ code Build เจอ ว่ามันใช้
libraspberry.Shell.ShellHost.GetUserId()
แล้วไป Excute command

ตัวอย่าง
echo "9SdD88y3O06WpE/6GFk2hA"; id -u; echo "hSi/cBNizkaFPRKwd4v2A"
เพื่อให้ได้
9SdD88y3O06WpE/6GFk2hA
(สมมติเป็น root)

hSi/cBNizkaFPRKwd4v2A

เพื่อเอา เฉพาะ 0 แต่ คงมีปัญหา อะไรซักอย่างกะ \n, whitespace blah blah
แก้โลด ถ้า throw error ก็ เจาะจงมันเป็น root ไปเลย



Error อันที่ 2 คือ cannot excute uname -a เพื่อ เอา architect
มันไปใช้
Microsoft.Build.Raspberry.Tasks.ValidateValidArchitecture.ExecuteTool()
ก็ เจาะจงมันเป็น x64_86 ไปเลย

แก้ไปแก้มา สรุป....ใช้ วิชวลจีดีบี ดีกว่า

7 มิ.ย. 2558

Unpack Data (Tree of Life)

เปิด Hex ดู Signature นู่นนี่นั่น


จริงๆ Google เจอว่า เฮีย luigi แห่ง quickbms ทำไว้แล้ว (ยังสดๆ ณ วันที่ 7/6/2558)
แต่ตอน unpack มาไฟล์มันเสีย และ structure ของ folder มันดูรวนๆ ไม่ตรงกับที่เห็นใน hex ของ exe


แต่ก็ยังได้ประโยชน์เพราะเราจะรู้ structure ของ ไฟล์ pack โดยที่ไม่ต้องเดาเอาเอง แต่กระนั้นแกะเองดูดีกว่า
ถ้าดู script ของ quickbms จะเห้นว่าใช้ unzip ไล่ดูใน olly ก็มีการ ใช้ lib zlib 

และไปดูใน hex ของ data ก็จะเจอ  78 01 เต็มไปหมด


เพราะโดยปกติมันเป็น header ของ zlib คร่าวๆมี
78 01 - No Compression/low
78 9C - Default Compression
78 DA - Best Compression  
ฟันธงว่า zlib แน่นอน
เริ่มไปดูว่า เกมอ่าน data.pack ยังงัยที่ถูกต้อง พยายามหาว่า Code ที่เกี่ยวกับ Virtual File System มันอยู่ตรงไหน


ตรงนี้แน่นอน แตะเมื่อ google ดู ประกาฏว่ามันเป็น Open Source โชคดีจริงๆ ที่ dev ยัง เหลือ text ไว้ให้ตามร่องรอยได้
ก็โหลด code มาโม จน สามารถ unpack ได้อย่างถูกต้อง
และโครงสร้างที่ถูกต้องคือ


แต่มันยังไม่จบแค่นั้น เพราะ แต่ละไฟล์ยังถูก zip ไว้อีกชั้น



ในสองรูปแบบ
1.       คือไม่โดน compress  (smallshop.png) Offset ที่ 10 เป็นตัวบอกว่า มันโดน compress รึปล่าว
2.       คือโดน compress (build_list_icon.png)
ไฟล์ที่โดน compress สั่งเกต DWORD Offset ที่ 0  จะไม่เท่ากับ DWORD Offset  ที่ 6
DWORD Offset ที่ 0 น่าจะเป็นตัว บอก max size หลังจาก uncompress  ส่วน DWORD Offset ที่ 6 เป็นตัวบอก ขนาด binary ที่เป็น data ที่ compress อยุ่ (ลองนับ ตั้งแต่ 78 01 ไปจนถึงสุดไฟล์จะได้ขนาดเท่า DWORD Offset  6 พอดี )
ว่าแล้วก็เขียนโปรแกรมไล่ decompress ทีละไฟล์
แต่! ผลลัพท์ ออกมาเหมือนของ quickbms เลย คือมีไฟล์เสีย ที่ประมาณกลางๆ ไฟล์


มีสองเหตุผล ที่คิดออกที่เป็นแบบนี้
1.       Algorithm ในการ uncompress ของ zlib โดน custom (ทำให้ต้องไล่ reverse engineer code zlib ทั้งหมด ใน game client)
2.       Data ก่อน uncompress มันพังอยู่แล้ว ทำให้ uncompress ไม่ได้ (ทำให้ต้องไล่ reverse engineer OFS ทั้งหมด ใน game client และ ถ้าไม่ใช่ก็ต้องไล่หาว่า มันโดยแก้อะไรตรงไหนก่อน uncompress )
จากทางเลือกทั้งสองดูเหมือน ข้อ 1 จะมีปริมาณงานน้อยกว่า แต่จากการที่ไล่ดูหมดแล้ว บอกเลยดีกว่า ว่าหวยออกข้อ 2 แต่ไม่ใช่ ที่ตัว OFS แต่ เป็นที่กระบวนการ ก่อนการ uncompress  เราต้องไปแก้บาง byte ใน data ให้ถูกต้องก่อน uncompress

จะเริ่มไปใช้เครื่องมือที่ชื่อ IDA ในการ reverse engineer ที่เราจะหา code อะไรๆ ง่ายกว่า
ย้อนกลับไปตอนที่ เขียนโปรแกรม uncompress เอง ตัว zlib จะ return DATA_ERROR ออกมา เราก็ควรจะไปเริ่ม ที่ตรงแถวๆนั้นในการ reverse engineering ซึ่งก็คือแถวๆนี้  Address 0x6A4A1D

ปล. ปิด ASLR ซะจะได้ไล่ Address ง่ายๆ
จุดประสงค์คือจะไปดูว่าอะไร Call มัน


ไล่กลับไปเรื่อยๆ อย่างมีหลักการ ^^ ว่าออกจากส่วนที่เป็น zlib รึยัง หรือมีอะไรผิดปกติ ไป ก็จะเห็น


วิเคราะห์ ด้วย IDA และ Plugin HexRay C Decompile เพื่อความสะดวก
-          V8 = sub_61665E คือ new  แล้วจะได้ pointer กลับมาไว้ใน V8
-          Function ที่น่าสงสัยคือ sub_615F40 และ sub_615E10 เพราะมีการ ส่ง buffer ไปเป็น parameter ก่อนการ uncompress
-          Sub_6443B0 = คือ function ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen, const Bytef *source, uLong sourceLen)); ใน zlib
ไปดูที่ sub_615F40 ก่อน


Parameter a1 มันต้องเป็น pointer ของ struct ที่เก็บข้อมูลของแต่ละไฟล์ใน pack แน่นอน เพราะ เมื่อ debug ด้วย olly dbg ทำให้รู้ว่า v1 = *(DWORD*)(a1 + 16) คือ length ของชื่อไฟล์  
และ debug หา ตัวแปรอื่นใน struct ไปเรื่อยๆ ได้เป็น code นี้ในภาษา c

สรุป Function นี้จะเป็นการคำนวน key โดย parameter คือชื่อไฟล์ ในแบบ Unicode
มาต่อที่ function sub_615E10 ไอตัวนี้แหละไอตัวดีแน่นอนเพราะมันมีการแก้ binary ของไฟล์ก่อนการ uncompress


โดยจะรับ parameter a3 ที่เป็น key ที่ถูกคำนวนจากชื่อไฟล์
a1 คือ pointer ของ data , a2 คือ size ของ data
มันจะทำการแก้ไขให้ data ถูกต้อง โดยการ xor byte กลับมาจำนวน 6 byte
Code ใน c ก็ จะได้เป็น


เมื่อเขียนโปรแกรมเสร็จเรียบร้อยก็ทดลอง unpack ใหม่ 

ไม่พังแล้วจ้า!!!

วิธีการ pack กลับก็ย้อนกระบวนการกลับ โดยที่ไม่จำเป็นต้อง compress แล้วก็ได้  แค่เอาไปใส่ data.pack ไว้ จากเดิม data.pack ขนาดเดิมประมาณ 499MiB จะเป็นประมาณ 941MiB แต่ client ก็ยังอ่านได้เหมือนเดิม

ลองแก้อะไรดูซักหน่อย นั่นคือ ทำให้กลางคืนมันสว่างเหมือนกลางวันซะ ด้วยการแก้ data ใน pack 

22 ก.ย. 2557

std::vector splice ด้วย initialize_list กับ parameter pack

// testfunc.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

enum class Operation {
 DELETE, INSERT, EQUAL
};


class Diff
{
public:
 Diff()
 {

 }

 Diff(Operation oper, std::string & str)
 {
  operation = oper;
  text = str;
 }

 inline bool operator==(Diff & rhs)
 {
  return rhs.operation == operation && rhs.text == text;
 }

 Operation operation;
 std::string text;
};

template<class T>
std::vector<T> * SpliceIL(std::vector<T> * input, int start, int count, std::initializer_list<T> objects = {})
{
 std::vector<T> * delRange = new std::vector<T>(input->begin() + start, input->begin() + start + count);
 while (count > 0)
 {
  input->erase(input->begin() + start);
  count--;
 }
 for (auto i : objects)
 {
  input->insert(input->begin() + start++, i);
 }

 return delRange;
}

template<class T,typename... Args>
std::vector<T> * SplicePP(std::vector<T> * input, int start, int count, Args...objects)
{
 std::vector<T> * delRange = new std::vector<T>(input->begin() + start, input->begin() + start + count);
 std::vector<T> newVec = { objects... };
 while (count > 0)
 {
  input->erase(input->begin() + start);
  count--;
 }
 for (auto i : newVec)
 {
  input->insert(input->begin() + start++, i);
 }

 return delRange;
}

int _tmain(int argc, _TCHAR* argv[])
{
 std::vector<Diff*> * r1 = new std::vector<Diff*>();
 r1->push_back(new Diff(Operation::EQUAL,std::string("1")));
 r1->push_back(new Diff(Operation::EQUAL, std::string("2")));
 r1->push_back(new Diff(Operation::EQUAL, std::string("3")));
 r1->push_back(new Diff(Operation::EQUAL, std::string("4")));
 r1->push_back(new Diff(Operation::EQUAL, std::string("5")));
 r1->push_back(new Diff(Operation::EQUAL, std::string("6")));
 r1->push_back(new Diff(Operation::EQUAL, std::string("7")));
 r1->push_back(new Diff(Operation::EQUAL, std::string("8")));

 std::vector<Diff*> * r2 = SpliceIL<Diff*>(r1, 1, 2, 
        { new Diff(Operation::EQUAL, std::string("9")), 
         new Diff(Operation::EQUAL, std::string("10")) 
        } ); //!--pass
 std::vector<Diff*> * r4 = SpliceIL<Diff*>(r1, 1, 2, {}); //!--pass
 std::vector<Diff*> * r5 = SpliceIL<Diff*>(r1, 1, 2); //!--pass

 std::vector<Diff*> * r3 = SplicePP<Diff*, Diff*>(r1, 1, 2, 
        new Diff(Operation::EQUAL, std::string("12")), 
        new Diff(Operation::EQUAL, std::string("13")));
 std::vector<Diff*> * r6 = SplicePP<Diff*, Diff*>(r1, 1, 2, nullptr); 
 std::vector<Diff*> * r6 = SplicePP<Diff*, Diff*>(r1, 1, 2); //!--error
 return 0;
}