최근 회사 프로젝트에서 C# 어플리케이션을 obfuscate 하면서 알게 된 부분들을 정리한 포스트.

내 (얕은) 지식으로는 컴파일 언어는 “컴파일러를 통해 바이너리로 치환되서 컴파일된 결과물만 가지고 소스를 복구할 수 없다”고 알고 있었는데 현대 언어에서는 그게 그렇게 단순한 부분이 아닌 것 같다. C# 프로그램은 dll이든 exe든 디컴파일러를 통해 내부 구조를 볼 수 있다. 심지어 그런 디컴파일러가 불법적으로 암암리에 유포된다거나 하는 것이 아니라 무료로 공개되어 있기도 하고 다들 많이 사용하는 모양이다. (예를 들면, Jetbrain의 dotpeek.)

컴파일 언어인데 어떻게 가능하지

C# 왕초보라 정확한 설명인지는 잘 모르겠지만 이것저것 찾아서 읽어본 글에 따르면,

  • C#은 Common Language Runtime(CLR) 위에서 돌아가는 언어
  • CLR은 MS에서 Common Language Infrastructure(CLI)를 구현한 구현체
  • CLI 규격에 의해 C#도 메타데이터를 포함

C#의 경우 이 메타데이터가 가지는 장점으로 쉽게 reflection 가능한 구조로 되어 있고 이를 통해 어셈블리의 타입이나 멤버, 메소드, 심지어는 내부 로직까지도 들여다볼 수 있다고 한다.

좋은 일에 쓴다면 엄청난 효율을 만드는 장점이지만 내부 로직이 공개될 위험이 있다. 그래서 디컴파일을 방지할 수 있는가에 대한 답변을 SO에서 찾아봤는데 대부분 답변이 둘로 수렴했다. 하나는 obfuscate 난독화를 하는 것이고, 다른 하나는 PaaS로 서비스하라는 얘기였다. 현재 프로젝트는 장기적으로 PaaS로 가겠지만 일단은 전자의 방식을 사용하기로 결정했다.

C# 난독화

Obfuscation은 코드를 읽기 어렵게 만들어서 내부 로직을 쉽게 들여다볼 수 없게 만드는 과정이다. 메소드, 변수 등을 a, b, c 등으로 수정해서 무슨 로직으로 동작하는지 알아보기 어렵게 만드는 것이다. 목적은 다르지만 결과물로 보면 JavaScript에서 js minify 한 것과 비슷하다.

Obfuscate하는 도구는 시중에 엄청 많이 나와 있는데 Visual Studio 2012를 설치하면 포함되어 있는 Dotfuscator를 사용했다. Dotfuscator의 사용 방법은 파일 추가 > 결과물 위치 지정 > 실행, 3단계로 아주 단순하다.

dotfuscator

다만 Dotfuscator를 하게 되면 모든 클래스, 메소드 등 대부분의 명칭이 a, b, c 와 같이 변하기 때문에 문제가 되는 부분이 있을 수 있다. 가령 JSON을 사용하는 경우라면 Serialize 될 때 해당 멤버변수명을 그대로 사용해야 한다. 그런 경우 다음과 같이 attribute로 예외를 지정해주면 된다.

class PolicyContainer
{
    [Obfuscation(Feature = "renaming", Exclude = true)]
    public IList<POLICY> Policys;
...

위 attribute와 같이 작성하면 해당 변수는 obfuscate되지 않는다. ObfuscationAttribute Class에서 더 자세한 내용을 확인할 수 있다.

PHP를 대차게 까는 분들이 가끔 워드프레스 설치하는 환경을 물어보기도 하고 또 환경 설정을 알려주면 설치하면서도 잔소리를 계속 하길래 이런 도구를 소개하는 것도 도움이 될 것 같아 짧게 소개글을 남긴다.

이제는 일반적인 웹호스팅 비용이나 AWS, Azure와 같은 IaaS의 요금이랑 큰 차이가 없어지고 있는데다 오히려 후자가 저렴한 경우도 많다. 게다가 서버 환경 설정을 마음대로 할 수 없고 해당 호스팅 업체에서 제공하는 서비스가 제한적일 때도 많아서 자연스럽게 가상 서버 환경을 염두하게 된다.

요즘은 이미 호스팅 환경이 설치되어 있는 서버 이미지를 제공하는 경우도 있고 앱 컨테이너로 쉽게 올릴 수 있는 플랫폼을 제공하는 경우도 많지만 웹호스팅에서 옮겨오려고 고민하는 케이스에는 굉장히 거창하고 막막할 수 밖에 없다. 겨우 필요한건 MySQL, Apache, PHP 환경인데 1) 안전하고 제대로 설치하는게 맞는지, 2) 튜토리얼이 엄청 많은데 어느 글을 따라해야 하는지, 3) 매번 콘솔에서 작업해야 하는지 등 고민이 줄줄이 나온다.

이 문제를 간단히 해결해줄 호스팅 관리도구 VestaCP가 있다. (No strings attached.)

명령어 2줄로 LAMP 환경을 모두 설치해주고 함께 설치되는 관리자 화면은 아주 심플한데다 국내 웹호스팅에서 제공하는 기능 정도는 다 제공한다. (SSL 설정, cron 설정 같은 것도.) 추가적인, 세세한 설정이 필요하다면 여전히 콘솔을 통해 작업을 해야 하지만 워드프레스 사이트를 운영한다던지, 간단한 LAMP 환경 개발 같은 경우에는 별도의 수정 없이도 충분히 사용이 가능했다.

설치는 다음과 같이 가능하다.

# Download installation script
curl -O http://vestacp.com/pub/vst-install.sh
# Run it
bash vst-install.sh

AWS Free-tier를 사용해도 문제 없이 잘 돌아간다. EC2 Ubuntu 이미지라면 다음과 같이 설치해야 한다.

# Download installation script
curl -O http://vestacp.com/pub/vst-install.sh
# Run it
sudo bash vst-install.sh --force

회사에서 cPanel (&WHM)과 Plesk를 사용하고 있었다. 이 둘은 엄청나게 세세하고 다양한 기능을 제공하긴 하지만 최근 작업한 magento 기반 프로젝트들은 다른 사이트와 함께 쓰기에는 무거운 감이 있어서 별개의 가상서버를 사용하게 되었고 기존 사용하던 관리도구들이 비용 문제, 고사양이 필요한 문제가 있었다. 그래서 대안을 찾다 VestaCP를 알게 되었고 최근 구축한 사이트는 다 이 관리도구를 이용한 서버에서 운영하고 있다.

추가적인 설정이 필요한 경우 Vesta 문서를 참고하자.

한국의 의료보험과 같이 호주에서도 국가에서 제공하는, Medicare라는 의료보험이 있다. 이 비용을 세금을 환급받는 과정에서 공제하는 형태로 납부하게 되는데 호주 영주권자 혹은 시민권자가 아닌 경우에는 해당이 없는 부분이다. 그래서 세금 환급 양식을 작성할 때 Medicare levy exemption 항목을 작성해 납부되지 않도록 해야 한다.

회계사를 통해서 세금 환급을 하면 이런 부분에 대해 신경 쓸 필요가 없겠지만 내 경우에는 크게 복잡한 부분이 없으니 내 스스로 신청했다. 그러던 중 지난 회계년도에 myTax를 통해서 세금 환급을 신청하는 과정에서 양식을 임시로 저장하려다가 제출해버려서 Medicare levy exemption이 반영되지 않고 환급이 진행되었다.

세금 환급 중 내용을 잘못 기재해서 수정해야 하거나 추가해야 하는 경우에는 내용 정정 신청 (Amendment request)를 하면 된다. 정정 신청은 요청 양식을 출력해 각 항목을 작성한 후 ATO로 우편으로 발송하거나 팩스로 보내면 된다.

양식을 작성할 때 다른 부분은 개인 정보 적는 난이라 복잡한 부분이 없고 8번 왜 정정을 요청하는가에 대해서는 구구절절 쓰면 되고 10번 항목 정도가 막막한 부분이다. Qustion number from tax return, Alpha label on tax return 두 항목은 종이 양식에 나온 레이블을 참고해서 작성하면 된다. 내 경우에는 다음과 같이 작성했다.

Tax Amendment Request

글씨가… 아하하하하핳

세금 환급 메뉴얼에는 자국민이 아닌 사람의 Medicare levy exemption에는 추가적인 정보를 요구하지 않는데 나는 혹시나 하는 마음에 내 VEVO Entitlement Check를 출력해 위에서 작성한 양식과 같이 우편으로 보냈다.

소요되는 시간은 How we process your amendment request 에서 확인할 수 있는데 내가 잘못 작성했음 && 메일 접수에 해당해서 50일이 걸린다고 나왔고 실제로 추가 부분을 환급 받는데 그 정도 시간이 걸린 것 같다.

위 과정에서 막히는 부분이 있으면 ATO에 전화해서 물어보면 되고 번거로운 분들은 회계사 분들께 연락해서 해결하면 되겠다. 요즘은 개인 세금 환급도 저렴하게 해주는 회계사 분들도 많은데 다음엔 그 분들 통해서 일을 처리해야겠다고 느꼈다.

ConfigurationManager.appSettingsSerialize해서 다른 곳에 전송하는 것은 어떨까 하는 아이디어를 듣고 코드를 작성해 Json.NET을 사용해서 SerializeObject를 했다. appSettings는 NameValueCollection 클래스인데 Dictionary와 같이 serialize 될 것이라 예상했지만 결과는 키값만 배열로 반환했다.

var col = new System.Collections.Specialized.NameValueCollection(){
    {"a", "Hello"}, {"a", "World"}
};

Console.WriteLine(JsonConvert.serializeObject(col));
// return "[\"a\"]"

NameValueCollection은 하나의 키에 여러개의 값을 가질 수 있는 컬렉션이기 때문에 Dictionary와는 다른 형태로 serialize되도록 NameObjectCollectionBase에서 구현되어 있는 것으로 보인다.

Console.WriteLine(col["a"]);
// return Hello,World

동일한 키라도 각각의 값이 독립적으로 보장되야 한다면 조금 복잡해지겠지만 내 경우에는 위와 같이 ,로만 구분 되어도 큰 문제가 없는 상황이라서 Dictionary로 변환한 후에 Serialize하는 방법으로 문제를 해결했다.

var dict = col.AllKeys.ToDictionary(k => k, v => col[v]);

Console.WriteLine(dict["a"]);
// return Hello,World

Console.WriteLine(JsonConvert.serializeObject(dict));
// return "{\"a\":\"Hello,World\"}"

동일한 키에 여러개의 값을 가지는 상황이라면 JSON에선 키 아래 배열로 변환되어야 의미론에 더 맞는 것 같다. 위와 같은 방법 말고도 더 아름답고 쉽고 시멘틱한 방법이 있을 것 같은데…


GetValues(key)를 이용하면 string[]으로 반환해준다고 한다. how to convert NameValueCollection to JSONstring의 코드를 참고하면 되겠다.

C#을 쓸 일이 종종 있는데 아직 초보 수준이라서 모르는 문법이 많다. 코드를 읽다가 메서드 선언 앞에 나온 물결 문자를 보게 되었는데 관련된 내용을 찾아봤다. 다음 내용은 함수명 앞에 오는 물결 표시는 무슨 의미인가요?에 나온 답변이다.

C#에서 메소드 선언 앞에 나오는 ~(물결 문자, 틸드)는 소멸자다.

  • 소멸자는 자동으로 동작하며 명시적으로 실행할 수 없다.
  • 소멸자는 오버로드가 불가능하다. 그러므로 클래스는 최대 하나의 소멸자를 가질 수 있다.
  • 소멸자는 상속되지 않는다. 그러므로 클래스는 하나 이외의 소멸자를 가지지 않게 되고 그 소멸자는 해당 클래스에서 선언이 되어야만 한다.
  • 소멸자는 구조체에서는 사용할 수 없다. 클래스에서만 사용 가능하며 어떤 코드에서도 더 이상 인스턴스를 사용하지 못하게 될 때 소멸될 자격이 주어진다.
  • 인스턴스의 소멸자는 인스턴스가 소멸될 자격만 된다면 언제든 실행이 된다.
  • 인스턴스가 소멸될 때 소멸자는 상속 체인을 따라 자식-부모 순으로 순차적으로 호출된다.

Finalize

C#에서 Finalize 메소드는 표준 C++ 소멸자처럼 동작한다. C#에서는 Finalize라고 메소드에 이름 붙이는 것 대신 C++의 소멸자 문법처럼 물결 표시를 메소드명 앞에 붙인다.

Dispose

객체를 정리하기 위해 명시적으로 호출이 가능한 메소드 Close() 또는 Dispose()를 제공하는 것이 바람직하다. 소멸자는 GC에 의해 호출되기 때문이다.

IDisposable 인터페이스는 클래스가 가지고 있는 자원이 정리되어야 한다는 것을 알려주며 실제로 정리될 수 있는 방법을 제공해준다. 만약 소멸자를 직접 구현해야 한다면 그 클래스의 정리(Dispose) 메소드는 GC.SuppressFinalize() 메소드를 꼭 실행해 인스턴스를 강제적으로 제거해야 한다.

What to use?

명시적으로 소멸자를 호출하는 것은 허용되지 않는다. 소멸자는 가비지 컬렉터에 의해 호출된다. 만약 file을 다루는 것과 같이 처리 비용이 비싸 관리되지 않는 자원들을 다루게 되면 가능한한 빠르게 닫고 정리하기를 원할 것이다. 이런 경우에는 IDisposable 인터페이스를 구현해야 한다.


정말 상속되지 않는가

MSDN의 Destructors (C# Programming Guide)의 예제를 보면 상속은 아니지만 상속 순서에 따른 연쇄 호출(chaining)이 발생한다. 호출의 순서는 가장 하위 클래스의 소멸자부터 상위 클래스로 연쇄적으로 호출한다.

class First
{
    ~First()
    {
        System.Diagnostics.Trace.WriteLine("First's destructor is called.");
    }
}

class Second : First
{
    ~Second()
    {
        System.Diagnostics.Trace.WriteLine("Second's destructor is called.");
    }
}

class Third : Second
{
    ~Third()
    {
        System.Diagnostics.Trace.WriteLine("Third's destructor is called.");
    }
}

class TestDestructors
{
    static void Main()
    {
        Third t = new Third();
    }

}
/* Output (to VS Output Window):
    Third's destructor is called.
    Second's destructor is called.
    First's destructor is called.
*/

요즘은 이와 관련된 웹서비스가 많이 있어서 별도로 프로그램을 설치할 필요 없이 쉽게 이용 가능하다. 다만 업로드할 수 있는 용량에 제한이 있는 경우가 많아서 로컬에서 사용할 수 있는 방법을 찾아봤다.

PDF 파일의 정보를 확인하거나 추출하기 위해서 pdffonts를 사용할 수 있는데 과거엔 xpdf 라이브러리에 포함되어 있다가 현재에는 poppler 라이브러리를 설치해 사용할 수 있다. 이 라이브러리는 homebrew를 통해 쉽게 설치할 수 있다.

brew install poppler

폰트 정보를 알아내기 위해서는 다음과 같이 사용할 수 있다.

pdffonts <파일명>

이미지를 추출할 때는 다음과 같이 쓸 수 있다.

pdfimages <파일명> <추출 경로>

추출된 이미지가 ppm인 경우는 일반적으로 사용 가능한 포맷인 jpg로 변경해 사용 가능하다. 이 경우엔 imagemagick 라이브러리에 포함되어 있는 convert를 사용할 수 있다.

해당 라이브러리가 설치되어 있지 않다면 역시 brew를 통해 설치할 수 있다.

brew install imagemagick

설치가 완료되었으면 다음과 같은 명령어로 일괄 변환할 수 있다.

convert *.ppm image%d.jpg

여기서 사용된 라이브러리들은 리눅스 패키지 매니저에서도 설치 가능하다.

WordPress에는 기본적으로 Links라는 포스트 타입이 존재했었는데 WordPress 3.5 에서 제외되었다고 한다. 대부분의 사용자가 거의 이용하지 않는 기능이 되다보니 이런 결정을 내리지 않았나 싶다.

그 이전 버전 사용자는 업그레이드 하더라도 해당 기능이 계속 유지되지만 신규로 설치한 경우는 다음과 같은 Links 항목을 관리자 화면에서 찾을 수 없다. 이 Links 항목을 보여주는 Link Widget(Blogroll) 또한 존재하지 않는다.

3.5 이후 버전을 설치한 경우에는 Links가 존재하지 않는다.

티켓 #21307에서 논의된 결과로 Link Manager 플러그인으로 분리되었고 3.5 이후 버전에서는 해당 플러그인을 설치해 사용할 수 있다.

Press This는 워드프레스 2.6에서 Press It를 대체하기 위해 나온 기능 중 하나로 워드프레스에 내용을 공유할 수 있도록 돕는 북마클릿 기능이다. 이 북마클릿을 이용하면 어느 웹페이지도 간편하게 스크랩해 자료를 모으거나 해당 컨텐츠를 인용해 포스팅하는데 활용할 수 있다. 그 외에도 언제든 작성할 내용이 생각나거든 북마클릿만 눌러 간편하게 메모할 수 있는 편리한 기능 중 하나다.

설치하기

관리자 메뉴 중 Tools > Available Tools에서 Press This 섹션을 찾을 수 있다. 설명대로 Press This 버튼을 bookmark bar에 끌어다 놓으면 설치가 끝난다. (drag and drop)

(Scrapbook 플러그인을 설치하면 똑같은 페이지에 Scrap This 버튼이 생겨난다. 이 버튼으로 북마클릿을 만들면 Post가 아닌 Scrap으로 수집할 수 있다.)

press-this

활용 방법

저장하려고 하는 페이지에서 북마크바에 끌어다 놓았던 북마클릿을 실행하면 작은 에디터 창이 나타난다. 바로 포스트 하거나 카테고리, 태그 등을 이용해 분류할 수도 있다. 인용하고 싶은 구절이 있다면 해당 영역을 드래그 한 후 북마클릿을 누르면 아래와 같이 간편하게 인용할 수 있다.

press-this-window

트위터, 페이스북, pocket 전부 관리되지 않는 스크랩 자료로만 가득 차는 기분이 들어서 워드프레스에서 수집할 수 있도록 작은 플러그인을 만들었다.

플러그인은 scrap이라는 포스트 타입을 생성해주며 일반 포스트와 동일하게 category와 tag를 지원한다. 추가적으로 워드프레스에서 post에서 사용할 수 있는 함수를 비슷하게 쓸 수 있도록 이름만 바꿔서 같이 넣었다. 기본적인 widget도 포함하고 있다.

플러그인은 gist 에서 받을 수 있으며 소스코드도 확인 할 수 있다.

2014년 10월 7일 업데이트: 플러그인을 GitHub 리포지터리로 옮기고 bookmarklet을 활용할 수 있도록 Scrap this를 추가했다. 다운로드는 여기에서, 코드는 github에서 확인할 수 있다.


이 블로그와 같이 scrap archive를 만들기 위해서는 해당 테마에 새로운 포스트 타입과 taxonomy를 위한 페이지를 생성해야 하며 생성할 때 the_tag()와 같은 함수들을 the_scrap_tag()와 같이 변경해줘야 한다.

  • archive.php -> archive-scrap.php, taxonomy-scrap_category.php, taxonomy-scrap_tag.php
  • single.php-> single-scrap.php
  • sidebar.php -> sidebar-scrap.php

물론 생성하지 않아도 출력은 되지만 약간 다르게 나오는 부분들이 있다. (원래는 자동으로 뿅 되야 하는데 대충 만들어서… 추후 버전을 기약하며.)

이 플러그인을 위한 특정 Permalink를 사용하려면 Custom Post Type Permalinks 플러그인을 활용할 수 있다.

멜번에 영사관이 생겨 영사 업무를 시작했는데 한국 운전면허증 공증도 받을 수 있다고 하길래 다녀왔다. 1949년 제네바에서 체결된 「도로교통에 관한 협약」에 따라 제네바 협약국 간 운전면허를 인정해준다. 한국 호주 모두 협약국이기 때문에 한국 운전면허증과 공증 서류를 가지고 호주 운전면허증을 대신해 사용할 수 있다.

공증에 필요한 준비물은 다음과 같다.

공증 절차도 영사관 웹사이트에 잘 설명되어 있다.

멜번 영사관은 Level 10, 636 St Kilda Rd, Melbourne VIC 3004에 위치하고 있다. St kilda Rd 끝자락에 있어 시티 반대 방향 3번, 5번, 16번 트램을 타고 Union St/St Kilda Rd에서 내리면 된다. 지도에서는 St Kilda Junction 정거장이 가까운데 길 건너는 것이 불편하다. 트램 정거장에서 5분 정도 걸으면 되는 거리라 크게 멀지 않다.

멜번 영사관이 있는 636 St Kilda Rd

멜번 영사관 입구

멜번 영사관

위에서 준비해 간 양식을 제출하면 담당 공무원이 검사를 하고서(?) 인지 붙이고 도장을 찍어준다. 웹사이트에 올라온 예제대로 작성하면 담당 공무원이 틀렸다고 다시 작성하라고 얘기할 것이다. 다행히 민원용 컴퓨터가 비치되어 있어 바로 출력할 수 있지만 그래도 미리 서류를 준비하고자 하려 한다면 다음 방식으로 작성하면 된다.

  • 항목은 모두 영어로 적는다. (예제 양식에 속지 말자.)
  • 주소는 영어로 적되 영어 주소처럼 역순으로 적는다.
  • 모든 일자는 일월년 순으로 적는다. (02-11-2014)
  • 만료일은 적성검사 기간을 적는다.
  • 면허 번호의 지역명도 영어로 적는다.
  • 서명칸은 검사 다 받고 서명해야 하므로 공란으로 둔다.

잘못 작성했다고 갈구는 한국식 친절(?)을 오랜만에 경험할 수 있었고 덕분에 빠르게 문서를 발급 받을 수 있었다.

방문하지 않고도 우편으로도 가능한데 절차는 영사관 웹페이지에서 확인할 수 있다. (사이트에 게시된 내용과 다를 가능성이 높기 때문에 전화로 문의하자.)

주소 : Level 10, 636 St Kilda Rd, Melbourne VIC 3004

업무시간 : 9:00 am – 12:00am, 1:00 pm – 5:00 pm (월-금)

전화번호 : (61 3) 9533 – 3800

영사민원전화 : (61 3) 9533 – 3803/3804

기업지원담당관 : (61 3) 9533-3813

팩스번호 : (61 3) 9533 – 3801

웹사이트 : http://mel.mofa.go.kr/

색상을 바꿔요

눈에 편한 색상을 골라보세요 :)

Darkreader 플러그인으로 선택한 색상이 제대로 표시되지 않을 수 있습니다.