티스토리 뷰
728x90
    
    
  반응형
    
    
    
  NONAME을 이용한 멀티스레드 세이프한 방법
1. 멀티스레드 환경에서 발생할 수 있는 문제
- 동시 접근 문제: 여러 스레드가 동일한 자원에 동시에 접근할 경우, 데이터 불일치 또는 충돌이 발생할 수 있습니다.
 - 메모리 관리 문제: 객체의 생성과 해제를 DLL 내부에서 처리하지 않으면 메모리 누수나 충돌이 발생할 수 있습니다.
 - 전역 변수 사용: 전역 변수에 여러 스레드가 접근할 경우 동기화가 필요합니다.
 
2. 스레드 안전성을 확보하는 방법
- 객체의 독립성 유지: 각 스레드가 독립적으로 객체를 사용하고, 공유 자원에 접근할 때는 동기화를 적용합니다.
 - 동기화 메커니즘 사용: 
mutex,critical section등 동기화 메커니즘을 사용하여 스레드 간 충돌을 방지합니다. - DLL 내부에서 객체 관리: 객체의 생성과 해제를 DLL 내부에서 처리하여 일관된 메모리 관리가 가능합니다.
 
3. 예제 코드
1) DLL 내 클래스 정의 및 스레드 안전성 확보
먼저, DLL 내부에서 클래스를 정의하고, mutex를 사용하여 스레드 안전성을 보장합니다.
// MyDLL.cpp
#include <windows.h>
#include <iostream>
#include <mutex>
// 전역 뮤텍스 선언 (스레드 동기화를 위한)
std::mutex g_mutex;
// 간단한 클래스 A 정의
class A {
public:
    A() {
        std::cout << "A 생성자 호출됨!" << std::endl;
    }
    ~A() {
        std::cout << "A 소멸자 호출됨!" << std::endl;
    }
    void DoSomething() {
        std::cout << "A::DoSomething 호출됨!" << std::endl;
    }
};
// 클래스 포인터 반환 함수
extern "C" __declspec(dllexport) A* CreateClassA() {
    std::lock_guard<std::mutex> lock(g_mutex);  // 스레드 동기화
    return new A();
}
// 클래스 포인터 해제 함수
extern "C" __declspec(dllexport) void DeleteClassA(A* pA) {
    std::lock_guard<std::mutex> lock(g_mutex);  // 스레드 동기화
    delete pA;
}
    
    2) DEF 파일 설정 (NONAME 방식으로 export)
DLL의 DEF 파일을 사용하여 함수 이름 대신 Ordinal 값으로 함수들을 export합니다.
LIBRARY MyDLL
EXPORTS
    CreateClassA @1 NONAME
    DeleteClassA @2 NONAME
    
    3) 멀티스레드 애플리케이션에서 DLL 호출
멀티스레드 환경에서 DLL의 클래스를 호출하고, 각 스레드가 안전하게 클래스를 사용한 후 해제하는 코드입니다.
// main.cpp
#include <windows.h>
#include <iostream>
#include <thread>
class A;
typedef A* (*CreateClassA)();
typedef void (*DeleteClassA)(A*);
// 스레드에서 실행될 함수
void threadFunction(CreateClassA createClassA, DeleteClassA deleteClassA) {
    A* pA = createClassA();  // 클래스 A의 인스턴스 생성
    if (pA) {
        pA->DoSomething();   // 스레드에서 클래스 A의 메서드 호출
        deleteClassA(pA);    // 클래스 A의 인스턴스 해제
    }
}
int main() {
    // DLL 로드
    HMODULE hModule = LoadLibrary("MyDLL.dll");
    if (!hModule) {
        std::cerr << "DLL 로드 실패" << std::endl;
        return 1;
    }
    // Ordinal 값으로 함수 가져오기
    CreateClassA createClassA = (CreateClassA)GetProcAddress(hModule, MAKEINTRESOURCE(1));  // @1
    DeleteClassA deleteClassA = (DeleteClassA)GetProcAddress(hModule, MAKEINTRESOURCE(2));  // @2
    if (createClassA && deleteClassA) {
        // 5개의 스레드를 생성하고 각각 클래스 A 인스턴스를 생성하고 사용
        std::thread threads[5];
        for (int i = 0; i < 5; ++i) {
            threads[i] = std::thread(threadFunction, createClassA, deleteClassA);
        }
        // 모든 스레드 종료 대기
        for (auto& th : threads) {
            th.join();
        }
    }
    // DLL 언로드
    FreeLibrary(hModule);
    return 0;
}
    
    4. 보안 및 관리 측면
- 메모리 관리: 객체의 생성과 해제를 DLL 내부에서 처리하여 메모리 충돌과 누수를 방지할 수 있습니다.
 - 스레드 안전성: 동기화 메커니즘을 사용하여 여러 스레드가 동시에 DLL 자원에 접근할 때도 안전하게 동작합니다.
 - 보안 강화: NONAME 기술을 사용하여 함수 이름 대신 Ordinal 값으로 접근함으로써 함수 이름을 숨기고 보안을 강화할 수 있습니다.
 
5. 결론
NONAME 기술을 사용하여 DLL에서 멀티스레드 환경에서도 안전하게 클래스를 생성하고 관리할 수 있습니다. 동기화 메커니즘을 통해 스레드 간 충돌을 방지하고, 메모리 관리를 DLL 내부에서 처리하여 메모리 누수를 방지합니다. 이 방법은 보안을 중요시하는 환경에서 효과적일 수 있습니다.
728x90
    
    
  
					댓글
						
					
					
					
				
			반응형
    
    
    
  
										공지사항
										
								
							
							
							
								최근에 올라온 글
								
							
							
								
									최근에 달린 댓글
									
							
							
								- Total
 
- Today
 
- Yesterday
 
									링크
									
							
							
								
									TAG
									
							
							
							- 성산블루버블
 - 서귀포
 - 서귀포블루버블
 - 현포다이브
 - ip
 - 제주도
 - DLL
 - 패턴
 - OpenSource
 - RSA
 - 암호화
 - Windows
 - 리눅스
 - Thread
 - 윈도우
 - 디자인패턴
 - 스쿠버다이빙
 - 블루버블다이브팀
 - 블루버블다이빙팀
 - ReFS
 - 다이빙
 - 양파다이브
 - Build
 - Linux
 - C
 - 블루버블
 - C++
 - PowerShell
 - 울릉도
 - C#
 
| 일 | 월 | 화 | 수 | 목 | 금 | 토 | 
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 
| 9 | 10 | 11 | 12 | 13 | 14 | 15 | 
| 16 | 17 | 18 | 19 | 20 | 21 | 22 | 
| 23 | 24 | 25 | 26 | 27 | 28 | 29 | 
| 30 | 
									글 보관함
									
							
					