지돌이의 블로그 입니다!

소스 초반에..

import * as uuids from 'uuid';
const promiseMap: Map < string, any > = new Map();
const OrigPromise: PromiseConstructor = global.Promise as PromiseConstructor;
function arrayArguments(input: IArguments): any[] {
    const arr = [];
    for(let i=0; i<input.length; i++) {
        arr[i] = input[i];
    }
    return arr;
}
global.Promise = function(func: any) {
    const stack = new Error().stack;
    return new OrigPromise((resolve, reject) => {
        const uuid = uuids.v4();
        promiseMap.set(uuid, {
            uuid,
            stack
        });
        func(function() {
            promiseMap.delete(uuid);
            resolve.call(null, ...arrayArguments(arguments));
        }, (err: any) => {
            promiseMap.delete(uuid);
            reject(err);
        });
    });
}

참고로 위는 typescript 소스이다.

위 내용을 추가한 뒤에 멈춘 Promise를 보고 싶을 때 showPendingPromise()을 호출하면 된다.

대충

setTimeout(() => showPendingPromise(), 1000);

이렇게 몇초뒤에 출력해도 되구...

그럼 Promise를 생성한 스택프레임을 보여준다.

===== 추가 =====
Proxy가 사용가능한 경우 아래가 더 낫다

import * as uuids from 'uuid';
const promiseMap: Map < string, any > = new Map();
const OrigPromise: PromiseConstructor = global.Promise as PromiseConstructor;
function arrayArguments(input: IArguments): any[] {
    const arr = [];
    for(let i=0; i<input.length; i++) {
        arr[i] = input[i];
    }
    return arr;
}
function newPromise(func: any) {
    const stack = new Error().stack;
    return new OrigPromise((resolve, reject) => {
        const uuid = uuids.v4();
        promiseMap.set(uuid, {
            uuid,
            stack
        });
        func(function() {
            promiseMap.delete(uuid);
            resolve.call(null, ...arrayArguments(arguments));
        }, (err: any) => {
            promiseMap.delete(uuid);
            reject(err);
        });
    });
}

function showPendingPromise() {
    for (let item of promiseMap.entries()) {
        console.log(item[1]);
    }
}

setInterval(() => showPendingPromise(), 3000);

(global as any).Promise = new Proxy((global as any).Promise, {
    construct(target: any, argArray: any, newTarget?: any): object {
        return newPromise(argArray[0]);
    }
});

Comment +0

helm으로 bitnami/mariadb-galera를 설치했을 때 아래와 같은 오류가 난다. (2020-04-23기준 mariadb-galera-2.0.1 차트)

 

(bitnami github에서 받아서 설치하면 Access denied 'root'... 오류가 난다.. 그냥 github안쓰고 직접 해야 오류 안난다..

WSREP_SST: [ERROR] xtrabackup_checkpoints missing, failed innobackupex/SST on donor (20200423 05:34:56.967)
WSREP_SST: [ERROR] Cleanup after exit with status:2 (20200423 05:34:56.969)

 

이런 경우 helm install 하자마자 statefulset의 replica를 1로 바꾼뒤에 첫번째 파드가 뜨면 해당 mysql 서버에 접속해서 mariabackup 사용자에 PROCESS, RELOAD 권한을 추가한 뒤 적용하고 replica를 원래걸로 바꾸면 된다.

Comment +0

https://bintray.com/jc-lab/java-utils/asn1-stream-reader

 

Package asn1-stream-reader - jc-lab

 

bintray.com

 

전에 node.js 에서 ASN1을 Stream형태로 파싱하는 라이브러리를 만든 적이 있습니다.

https://ablog.jc-lab.net/219

 

asn1-stream: Node.JS asn1 stream 파서

https://www.npmjs.com/package/asn1-stream asn1-stream ASN1 parser with a stream interface www.npmjs.com asn1을 stream으로 파싱하는걸 찾았는데 없네요... infinite length 파싱은 구현은 대충 해 놓았지만..

ablog.jc-lab.net

이번에는 해당 라이브러리를 Java용 라이브러리로 만들었습니다.

jcenter에 배포되었으니 jcenter repository을 통해 사용하실 수 있습니다.

 

ASN1Object는 많이들 사용하시는 bouncycastle을 사용하기 때문에 불편함은 없을 것입니다.

 

infinite length(BER)/fixed length(DER) 형식 모두 지원하며 node.js용으로 만든 asn1-stream처럼 stripSequence 최상위 Sequence대신 그 하위 객체들을 리턴하는 기능 또한 지원합니다.

 

포함되어 있는 CallbackInputStream / QueueInputStream 등을 사용하여 폭넓게 원하시는 어플리케이션에 적용 가능하며 Callback을 통한 출력 및 Non-blocking 출력이 가능합니다. (애초에 Nonblocking 쓰려고 만든거라..ㅎㅎ bc의 ASN1InputStream은 Non-blocking이 안돼요ㅠㅠ)

Comment +0

github를 사칭한 피싱메일도 오네요..

 

실제 제가 github에서 사용하고 있는 메일 주소로 아래와 같은 메일이 왔습니다.

 

디자인이 깔끔해서 진짜같네요...ㅎㅎ

 

링크를 클릭하면 두번째 사진 페이지로 갑니다.

 

그런데 아무렇게나 입력하면 비밀번호가 틀렸다고 나오네요.. 보통 피싱사이트를 보면 무조건 맞다고 하거나 진짜 페이지로 니동시키는데 그러진 않습니다.

 

실제로 정보를 확인하는 것 일수도요..

 

암튼 이젠 계장탈취 뿐 아니라 소스까지 탐을 내나 봅니다.. 깃허브 피싱이라니.. 다들 조심하시길 바랍니다.

 

Comment +0

WIMCreateFile에는 CreateFile와는 달리 dwShareMode옵션이 없다.

 

이를 사용할 수 있는지 확인해 보기 위해 분석을 시도한다.

 

volatile const void* p_WIMCreateFile = WIMCreateFile;
const void* p_CreateFileW = CreateFileW;
HANDLE hTemp = CreateFileW(_T("E:\\ISO\\boot.wim"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
CloseHandle(hTemp);
HANDLE hWim = WIMCreateFile(_T("E:\\ISO\\boot.wim"), WIM_GENERIC_READ, WIM_OPEN_EXISTING, 0, 0, 0);
printf("hWim = %p\n", hWim);

 

일단 위 코드를 실행하고 VisualStudio Debug Window중에 디스어셈블창을 열어서 CreateFile의 구현에 브레이크를 건다.

 

[사진1] _CreateFileW@28에 브레이크가 걸린 모습

CreateFileW의 구조는 아래와 같다.

HANDLE CreateFileW(
  LPCWSTR               lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile
);

WIMFileCreateFile에서 _CreateFileW@28을 호출하는 부분을 보면..

[사진2] WIMFileCreateFile함수내에서 _CreateFileW@28 호출하는 부분

dwShareMode에 단순히 0이 아니라 *(ebp+8)의 값을 넣는것을 볼 수 있다. 희망이 있다!

 

[사진3] (사진2)에서 dwShareMode의 값

근데 값을 보면 이미 FILE_SHARE_READ 가 있다... 근데 왜 CreateFile으로 열고 있으면 WIMCreateFile이 안되었던 거지??? 뭔가 잘못했었나 보다...ㅠㅠ

 

아쉬우니 좀더 뒤져보면...

 

v7 = GetWimDesiredAccess(v3) & 0x40000000 /* GENERIC_WRITE */;
v20 = (v7 == 0) ? FILE_SHARE_READ : 0;
if ( GetFlagsAndAttributes(v3) & 0x40 /* FILE_ATTRIBUTE_DEVICE */)
  dwShareMode = 3; // FILE_SHARE_READ | FILE_SHARE_WRITE
else
  dwShareMode = v20;

결국...
GENERIC_WRITE가 없으면 FILE_SHARE_READ를 자동으로 넣는다.

 

끝.

Comment +0