获取程序入口点

入口点介绍

一个程序从最开头往下算大致可以分为DOS头,DOS头相关数据,PE头,然后才是文件数据,我们要找的入口点地址写在了PE头里面。DOS头的长度是固定的,但其相关数据是不固定的,好在DOS头里有一个LONG类型的e_lfanew,这个变量记载了PE头相对DOS头的偏移。

IMAGE_NT_HEADERS是PE头结构体的宏,在32位和64位下分别对应_IMAGE_NT_HEADERS和_IMAGE_NT_HEADERS64。

typedef struct _IMAGE_NT_HEADERS {

    DWORD                         Signature;

    IMAGE_FILE_HEADER             FileHeader;

    IMAGE_OPTIONAL_HEADER32       OptionalHeader;

} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

Signature是任何程序里都是固定不变的,就是ASCII的“PE”两个字

FileHeader对应的东西用不到不作说明

OptionalHeader结构体里的AddressOfEntryPoint是入口点。

获取入口点

获取到入口点,要么你自己一层层调用得到入口点地址,要么就用API。

1. API——ImageLoad()函数

头文件ImageHlp.h

        ImageLoad(

            _In_ PCSTR DllName,

            _In_opt_ PCSTR DllPath

        );

就你填一个.exe文件地址和一个NULL,他最后返回给你一个LOADED_IMAGE结构体的指针,通过如下调用:

PLOADED_IMAGE image = ImageLoad("多字节字符集可执行文件地址",NULL);

DWORD dEnterPointer = image->FileHeader->OptionalHeader.AddressOfEntryPointer;

关于LOADED_IMAGE可以参考msdn介绍

这个dEnterPointer就是入口点地址了。

最后记得释放image:

ImageUnLoad(Image);

因为加载文件头的本质就是把人家内存拷贝过来一份,用完了及时释放省的占地儿。

2. 不使用API的话就自己写一个ImageLoad

头文件:fstream.h

void* INJECT::ImageLoad(const wchar_t* filename){
    std::ifstream streamReader(filename, std::ios::binary);  //以二进制的形式读取文件
    streamReader.seekg(0, std::ios::end);                    //跳转到尾部
    unsigned filesize = streamReader.tellg();                //得到文件大小
    streamReader.seekg(0, std::ios::beg);                    //跳转到开始
    char* _data = new char[filesize];
    streamReader.read(_data, filesize);
    streamReader.close();
    return _data;
}

void INJECT::UnloadImage(void* _data){        
    delete[] _data;        
}

函数使用:

DWORD INJECT::GetEntryPoint(const wchar_t* filename){
void* image = ImageLoad(filename);//得到DOS头
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)image;//以IMAGE_DOS_HEADER解析信息
unsigned PEAddress = dosHeader->e_lfanew + (unsigned)image;//得到PE头
IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)PEAddress;  //以IMAGE_NT_HEADERS解析PE头
DWORD dEnterPoint = ntHeader->OptionalHeader.AddressOfEntryPoint;//获取PE头内的入口点地址
UnloadImage(image);//关闭文件
return dEnterPoint;
}

几个结构体的关系:

LOADED_IMAGE                        包含PIMAGE_NT_HEADERS32(PE头)

IMAGE_NT_HEADERS32           包含IMAGE_OPTIONAL_HEADER32(包含入口点位置的结构体)

IMAGE_OPTIONAL_HEADER32        包含DWORD类型的AddressOfEntryPoint(入口点)

API版的ImageLoad和手写的ImageLoad的区别且不谈,就获取到数据后的操作:

API:

DWORD dEnterPointer = image->FileHeader->OptionalHeader.AddressOfEntryPointer;

手写:

IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)image;                //以IMAGE_DOS_HEADER的形式解析信息

unsigned PEAddress = dosHeader->e_lfanew + (unsigned)image;                //得到PE头

IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)PEAddress;                //以解析PE头特有的结构解析PE头

DWORD dEnterPoint = ntHeader->OptionalHeader.AddressOfEntryPoint;        //获取PE头内的入口点地址

可以看出手写的函数,代码传回的是指向DOS头的指针而非PLOADED_IMAGE,这个LOADED_IMAGE结构体内部就有PE头的已经计算好的地址,而我们手写的话,得到了DOS头地址,需要用DOS头地址加上e_lfanew才能得到真正的PE头。

要使用AccessibilityNodeInfo获取程序入口,你可以按照以下步骤进行操作: 1. 获取AccessibilityService实例:首先,你需要在你的代码中获取AccessibilityService实例。这可以通过继承AccessibilityService类并实现其方法来实现。 2. 实现onAccessibilityEvent方法:在你的AccessibilityService类中,你需要实现onAccessibilityEvent方法。这个方法会在可访问事件发生时被调用。 3. 获取根节:在onAccessibilityEvent方法中,你可以通过调用getRootInActiveWindow()方法来获取当前窗口的根节。这个方法会返回一个AccessibilityNodeInfo对象,它表示当前窗口的界面元素树。 4. 遍历节树:一旦你获取了根节,你可以使用AccessibilityNodeInfo的方法来遍历整个节树。你可以使用getChildCount()方法获取子节数量,并使用getChild()方法来获取特定索引位置的子节。 5. 判断入口:在遍历节树的过程中,你可以使用AccessibilityNodeInfo的方法来判断每个节是否为程序入口。你可以使用getClassName()方法获取的类名,并使用getText()方法获取的文本内容。根据你的应用程序的特定情况,你可以使用这些信息来判断节是否为程序入口。 请注意,具体的实现细节可能会因为你的应用程序的特定情况而有所不同。你可能需要根据你的应用程序的界面结构和节属性来编写特定的代码逻辑来获取程序入口
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值