ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • kaitai struct로 binary 파일 읽기(wtmp)
    Node.js/예제 2021. 4. 11. 13:20

    kaitai sturct는 binary 데이터 파일을 해석하는 기능을 지원한다.

    (kaitai struct에 대한 자세한 내용은 사이트 참조: kaitai.io/)

    이 kaitai struct를 사용해서 binary 데이터 파일인 wtmp를 읽어볼 것이다.

    리눅스에서는 로그인/로그아웃 등 사용자의 접근 관련 기록이 /var/log 경로 내 wtmp, utmp 등의 파일에 기록되는데, 이 파일들은 binary 데이터로 이루어져 있다. 따라서 그냥 텍스트 에디터를 통해 읽으면

    읽을 수 없는 형태로 출력이 된다.

    따라서 이 데이터를 읽을 수 있는 데이터로 해석을 해야 하는데 이 때 사용하면 편리한 것이 kaitai struct다.

     

    사이트 상단에 Format Gallery를 클릭하면 다음 화면이 뜬다.

    리눅스 로그파일을 읽을 것이므로 Logs 항목의 glibc_utmp를 선택한다.

     

     

    선택해서 페이지를 이동하면 기본적으로 overview 탭 항목이 선택되어 있는데, 이 탭에서는 해당 데이터에 대한 대략적인 설명이 나오고, 데이터를 구성하고 있는 각 항목이 어떤 유형이고 얼마만큼의 크기를 차지하는지에 대한 그림을 보여준다.

    하단의 block diagram은 데이터가 어떻게 구성되어 있는지를 보여주는 이미지다.

     

    여기서는 node.js로 파일을 읽을 것이므로 JavaScript 탭을 선택한다.

     

    사용법대로 우선 kaitai-struct 모듈을 npm으로 설치한다.

    스크롤을 아래로 내리면 GlibcUtmp.js 전체 코드가 나오는데 이 코드를 모두 복사해서 파일명을 GlibcUtmp.js로 하여 저장한다.

     

    윈도우에서 테스트를 하기 위해 wtmp 파일을 옮겨와서 저장을 하였다. 리눅스에서 직접 테스트를 하려면 해당 파일의 위치를 직접 지정해주면 된다(/var/log/wtmp).

     

    const fs = require('fs');
    const moment = require('moment');
    const GlibcUtmp = require('./GlibcUtmp.js');
    const KaitaiStream = require('kaitai-struct/KaitaiStream');
    const wtmp = fs.readFileSync('./binary/wtmp');
    const data = new GlibcUtmp(new KaitaiStream(wtmp));

    코드 상단에 모듈 설정을 한다. moment는 시간 데이터 해석에 사용하기 위해 별도로 설치한 것이다. 필수가 아니니 생략해도 된다.

    위에서 data를 그대로 console.log로 출력하면 여러가지 필드가 출력되는 것을 확인할 수 있다. 그 중 해석된 데이터는 records라는 필드에 저장되어 있는데, 각 행위(로그인, 로그아웃 등)에 대한 데이터가 저장되어있는 하나의 배열이다. 이 배열 내 각각의 데이터는 위의 block diagram 이미지에서 설명하는 필드명 항목에 해당하는 데이터를 저장하고 있다.

     

    const entryType = [
      "EMPTY",
      "RUN_LVL",
      "BOOT_TIME",
      "NEW_TIME",
      "OLD_TIME",
      "INIT_PROCESS",
      "LOGIN_PROCESS",
      "USER_PROCESS",
      "DEAD_PROCESS",
      "ACCOUNTING",
    ];
    for (let i = 0; i < data.records.length; i++) {
      let { utType, pid, line, id, user, host, exit, session, tv } = data.records[i];
      line = line.replace(/\u0000/g, "");
      id = id.replace(/\u0000/g, "");
      user = user.replace(/\u0000/g, "");
      host = host.replace(/\u0000/g, "");
      const time = moment(tv.sec * 1000).add(9, 'hours').format("YYYY-MM-DDTHH:mm:ss");
      const tvsec = tv.sec;
      const res = { utType, pid, line, id, user, tvsec, host, exit, session, time };
      res.entryType = entryType[utType];
    
      console.log(res)
    }

    records를 순회하여 각 데이터를 파싱하면서 출력한다.

    console.log로 출력을 하면 위와 같은 형태로 출력되는 것을 확인할 수 있다.

Designed by Tistory.