PE查看器
主要界面如下:

主要代码如下:
BOOL CPEParseDlg::OnInitDialog()
{
CDialog::OnInitDialog(); // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码
InitSectionList(); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
} // 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。 void CPEParseDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), ); // 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + ) / ;
int y = (rect.Height() - cyIcon + ) / ; // 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
} //当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CPEParseDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
} void CPEParseDlg::OnBnClickedButtonLook()
{
// TODO: 在此添加控件通知处理程序代码
((CEdit*)GetDlgItem(IDC_EDIT_FILEPATH))->GetWindowText(m_strPathName);
m_strPathName = m_strPathName.Trim();
if (m_strPathName.IsEmpty())
{
AfxMessageBox(_T("请选择要查看的文件!"));
return;
} FileCreate();
if (FALSE == IsPeFileAndGetPePointer())
{
AfxMessageBox(_T("该文件不是PE文件!"));
return;
}
ParseBasePe();
EnumSections();
} void CPEParseDlg::OnBnClickedButtonExit()
{
// TODO: 在此添加控件通知处理程序代码
OnOK();
} void CPEParseDlg::OnBnClickedButtonBrowse()
{
// TODO: 在此添加控件通知处理程序代码
CFileDialog FileDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, _T("Executeable Files (*.exe)|*.exe|Dynamic Linker Library Files (*.dll)|*.dll|OCX Files (*.ocx)|*.ocx|Driver Files (*.sys)|*.sys||"));
FileDlg.DoModal();
CString strPathName = FileDlg.GetPathName();
((CEdit*)GetDlgItem(IDC_EDIT_FILEPATH))->SetWindowText(strPathName);
} BOOL CPEParseDlg::FileCreate(void)
{
BOOL bRet = FALSE; m_hFile = CreateFile(m_strPathName.GetBuffer(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == m_hFile)
{
return bRet;
} m_hMap = CreateFileMapping(m_hFile, NULL, PAGE_READWRITE, , , NULL);
if (NULL == m_hMap)
{
CloseHandle(m_hFile);
return bRet;
} m_lpBase = MapViewOfFile(m_hMap, FILE_MAP_READ | FILE_MAP_WRITE, , , );
if (NULL == m_lpBase)
{
CloseHandle(m_hMap);
CloseHandle(m_hFile);
return bRet;
} bRet = TRUE;
return bRet;
} void CPEParseDlg::InitSectionList(void)
{
CRect Rect;
m_ctrlSections.GetClientRect(&Rect);
m_ctrlSections.SetExtendedStyle(m_ctrlSections.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
m_ctrlSections.InsertColumn(, _T("节名"));
m_ctrlSections.InsertColumn(, _T("V.偏移"));
m_ctrlSections.InsertColumn(, _T("V.大小"));
m_ctrlSections.InsertColumn(, _T("R.偏移"));
m_ctrlSections.InsertColumn(, _T("R.大小"));
m_ctrlSections.InsertColumn(, _T("标志"));
m_ctrlSections.SetColumnWidth(, Rect.Width() / );
m_ctrlSections.SetColumnWidth(, Rect.Width() / );
m_ctrlSections.SetColumnWidth(, Rect.Width() / );
m_ctrlSections.SetColumnWidth(, Rect.Width() / );
m_ctrlSections.SetColumnWidth(, Rect.Width() / );
m_ctrlSections.SetColumnWidth(, Rect.Width() / );
} BOOL CPEParseDlg::IsPeFileAndGetPePointer(void)
{
BOOL bRet = FALSE; m_pDosHeader = (PIMAGE_DOS_HEADER)m_lpBase;
if (IMAGE_DOS_SIGNATURE != m_pDosHeader->e_magic)
{
return bRet;
} m_pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)m_lpBase + m_pDosHeader->e_lfanew);
if (IMAGE_NT_SIGNATURE != m_pNtHeaders->Signature)
{
return bRet;
} m_pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)&(m_pNtHeaders->OptionalHeader) + m_pNtHeaders->FileHeader.SizeOfOptionalHeader); bRet = TRUE;
return bRet;
} void CPEParseDlg::ParseBasePe(void)
{
m_strEntryPoint.Format(_T("%08X"), m_pNtHeaders->OptionalHeader.AddressOfEntryPoint);
m_strImageBase.Format(_T("%08X"), m_pNtHeaders->OptionalHeader.ImageBase);
m_strLinkerVersion.Format(_T("%d.%d"), m_pNtHeaders->OptionalHeader.MajorLinkerVersion, m_pNtHeaders->OptionalHeader.MinorLinkerVersion);
m_strSectionNum.Format(_T("%02X"), m_pNtHeaders->FileHeader.NumberOfSections);
m_strFileAlignment.Format(_T("%08X"), m_pNtHeaders->OptionalHeader.FileAlignment);
m_strSectionAlignment.Format(_T("%08X"), m_pNtHeaders->OptionalHeader.SectionAlignment);
UpdateData(FALSE);
} void CPEParseDlg::EnumSections(void)
{
m_ctrlSections.DeleteAllItems(); CString strTemp;
int iSectionNumber = m_pNtHeaders->FileHeader.NumberOfSections; for (int i = ; i < iSectionNumber; ++i)
{
strTemp = m_pSectionHeader[i].Name;
m_ctrlSections.InsertItem(i, strTemp); strTemp.Format(_T("%08X"), m_pSectionHeader[i].VirtualAddress);
m_ctrlSections.SetItemText(i, , strTemp); strTemp.Format(_T("%08X"), m_pSectionHeader[i].Misc.VirtualSize);
m_ctrlSections.SetItemText(i, , strTemp); strTemp.Format(_T("%08X"), m_pSectionHeader[i].PointerToRawData);
m_ctrlSections.SetItemText(i, , strTemp); strTemp.Format(_T("%08X"), m_pSectionHeader[i].SizeOfRawData);
m_ctrlSections.SetItemText(i, , strTemp); strTemp.Format(_T("%08X"), m_pSectionHeader[i].Characteristics);
m_ctrlSections.SetItemText(i, , strTemp);
}
} void CPEParseDlg::OnBnClickedRadioVa()
{
// TODO: 在此添加控件通知处理程序代码
m_nSelected = ;
((CEdit*)GetDlgItem(IDC_EDIT_VA))->SetWindowText(_T(""));
((CEdit*)GetDlgItem(IDC_EDIT_RVA))->SetWindowText(_T(""));
((CEdit*)GetDlgItem(IDC_EDIT_FILEOFFSET))->SetWindowText(_T(""));
((CEdit*)GetDlgItem(IDC_EDIT_VA))->SetReadOnly(FALSE);
((CEdit*)GetDlgItem(IDC_EDIT_RVA))->SetReadOnly(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_FILEOFFSET))->SetReadOnly(TRUE);
} void CPEParseDlg::OnBnClickedRadioRva()
{
// TODO: 在此添加控件通知处理程序代码
m_nSelected = ;
((CEdit*)GetDlgItem(IDC_EDIT_VA))->SetWindowText(_T(""));
((CEdit*)GetDlgItem(IDC_EDIT_RVA))->SetWindowText(_T(""));
((CEdit*)GetDlgItem(IDC_EDIT_FILEOFFSET))->SetWindowText(_T(""));
((CEdit*)GetDlgItem(IDC_EDIT_VA))->SetReadOnly(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_RVA))->SetReadOnly(FALSE);
((CEdit*)GetDlgItem(IDC_EDIT_FILEOFFSET))->SetReadOnly(TRUE);
} void CPEParseDlg::OnBnClickedRadioFileoffset()
{
// TODO: 在此添加控件通知处理程序代码
m_nSelected = ;
((CEdit*)GetDlgItem(IDC_EDIT_VA))->SetWindowText(_T(""));
((CEdit*)GetDlgItem(IDC_EDIT_RVA))->SetWindowText(_T(""));
((CEdit*)GetDlgItem(IDC_EDIT_FILEOFFSET))->SetWindowText(_T(""));
((CEdit*)GetDlgItem(IDC_EDIT_VA))->SetReadOnly(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_RVA))->SetReadOnly(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_FILEOFFSET))->SetReadOnly(FALSE);
} void CPEParseDlg::OnBnClickedButtonCalc()
{
// TODO: 在此添加控件通知处理程序代码
m_strImageBase = m_strImageBase.Trim();
if (m_strImageBase.IsEmpty())
{
AfxMessageBox(_T("请先点击查看按钮!"));
return;
} CString strPathName;
((CEdit*)GetDlgItem(IDC_EDIT_FILEPATH))->GetWindowText(strPathName);
if (strPathName != m_strPathName)
{
AfxMessageBox(_T("你已经更换了PE文件,请先点击查看按钮!"));
return;
} DWORD dwAddr = ;
dwAddr = GetAddr();
int nInNum = GetAddrInSectionNum(dwAddr);
CalcAddr(nInNum, dwAddr);
} DWORD CPEParseDlg::GetAddr(void)
{
TCHAR szAddr[] = {};
DWORD dwAddr = ;
switch (m_nSelected)
{
case :
GetDlgItemText(IDC_EDIT_VA, szAddr, );
HexStrToInt(szAddr, &dwAddr);
break;
case :
GetDlgItemText(IDC_EDIT_RVA, szAddr, );
HexStrToInt(szAddr, &dwAddr);
break;
case :
GetDlgItemText(IDC_EDIT_FILEOFFSET, szAddr, );
HexStrToInt(szAddr, &dwAddr);
break;
} return dwAddr;
} int CPEParseDlg::GetAddrInSectionNum(DWORD dwAddr)
{
int nInNum = ;
int nSectionNum = m_pNtHeaders->FileHeader.NumberOfSections;
switch (m_nSelected)
{
case :
{
DWORD dwImageBase = m_pNtHeaders->OptionalHeader.ImageBase;
for (nInNum = ; nInNum < nSectionNum; nInNum++)
{
if (dwAddr >= dwImageBase + m_pSectionHeader[nInNum].VirtualAddress
&& dwAddr <= dwImageBase + m_pSectionHeader[nInNum].VirtualAddress
+ m_pSectionHeader[nInNum].Misc.VirtualSize)
{
return nInNum;
}
}
break;
}
case :
for (nInNum = ; nInNum < nSectionNum; nInNum++)
{
if (dwAddr >= m_pSectionHeader[nInNum].VirtualAddress
&& dwAddr <= m_pSectionHeader[nInNum].VirtualAddress
+ m_pSectionHeader[nInNum].Misc.VirtualSize)
{
return nInNum;
}
}
break;
case :
for (nInNum = ; nInNum < nSectionNum; nInNum++)
{
if (dwAddr >= m_pSectionHeader[nInNum].PointerToRawData
&& dwAddr <= m_pSectionHeader[nInNum].PointerToRawData
+ m_pSectionHeader[nInNum].SizeOfRawData)
{
return nInNum;
}
}
break;
} return -;
} void CPEParseDlg::CalcAddr(int nInNum, DWORD dwAddr)
{
DWORD dwVa = ;
DWORD dwRva = ;
DWORD dwFileOffset = ; switch (m_nSelected)
{
case :
dwVa = dwAddr;
dwRva = dwVa - m_pNtHeaders->OptionalHeader.ImageBase;
dwFileOffset = m_pSectionHeader[nInNum].PointerToRawData + (dwRva - m_pSectionHeader[nInNum].VirtualAddress);
break;
case :
dwVa = dwAddr + m_pNtHeaders->OptionalHeader.ImageBase;
dwRva = dwAddr;
dwFileOffset = m_pSectionHeader[nInNum].PointerToRawData + (dwRva - m_pSectionHeader[nInNum].VirtualAddress);
break;
case :
dwFileOffset = dwAddr;
dwRva = m_pSectionHeader[nInNum].VirtualAddress + (dwFileOffset - m_pSectionHeader[nInNum].PointerToRawData);
dwVa = dwRva + m_pNtHeaders->OptionalHeader.ImageBase;
break;
} SetDlgItemText(IDC_EDIT_SECTION, CString(m_pSectionHeader[nInNum].Name)); CString str;
str.Format(_T("%08X"), dwVa);
SetDlgItemText(IDC_EDIT_VA, str); str.Format(_T("%08X"), dwRva);
SetDlgItemText(IDC_EDIT_RVA, str); str.Format(_T("%08X"), dwFileOffset);
SetDlgItemText(IDC_EDIT_FILEOFFSET, str);
} void CPEParseDlg::HexStrToInt(TCHAR* szAddr, DWORD* pdwAddr)
{
int iLen = lstrlen(szAddr);
*pdwAddr = ; for (int i = ; i < iLen; i++)
{
if (szAddr[i] >= _T('') && szAddr[i] <= _T(''))
{
*pdwAddr = ((*pdwAddr) << ) | (szAddr[i] - _T(''));
}
else if (szAddr[i] >= _T('A') && szAddr[i] <= _T('F'))
{
*pdwAddr = ((*pdwAddr) << ) | (szAddr[i] - _T('A') + 0xA);
}
else if (szAddr[i] >= _T('a') && szAddr[i] <= _T('f'))
{
*pdwAddr = ((*pdwAddr) << ) | (szAddr[i] - _T('a') + 0xA);
}
}
} void CPEParseDlg::OnDestroy()
{
CDialog::OnDestroy(); // TODO: 在此处添加消息处理程序代码
if (NULL != m_lpBase)
{
UnmapViewOfFile(m_lpBase);
} if (NULL != m_hMap)
{
CloseHandle(m_hMap);
} if (INVALID_HANDLE_VALUE != m_hFile)
{
CloseHandle(m_hFile);
}
} HBRUSH CPEParseDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); // TODO: 在此更改 DC 的任何属性
//if (nCtlColor == CTLCOLOR_DLG || nCtlColor == CTLCOLOR_STATIC || nCtlColor == CTLCOLOR_EDIT)
//{
// pDC->SetBkMode(TRANSPARENT);
// return CreateSolidBrush(RGB(0x2F, 0x4F, 0x4F));
//} // TODO: 如果默认的不是所需画笔,则返回另一个画笔
return hbr;
} void CPEParseDlg::OnBnClickedButtonAddsection()
{
// TODO: 在此添加控件通知处理程序代码
m_strImageBase = m_strImageBase.Trim();
if (m_strImageBase.IsEmpty())
{
AfxMessageBox(_T("请先点击查看按钮!"));
return;
} CString strPathName;
((CEdit*)GetDlgItem(IDC_EDIT_FILEPATH))->GetWindowText(strPathName);
if (strPathName != m_strPathName)
{
AfxMessageBox(_T("你已经更换了PE文件,请先点击查看按钮!"));
return;
} TCHAR szSectionName[] = {};
int nSectionSize = ; GetDlgItemText(IDC_EDIT_SECTIONNAME, szSectionName, );
nSectionSize = GetDlgItemInt(IDC_EDIT_SECTIONSIZE, FALSE, TRUE); AddSection(szSectionName, nSectionSize);
} void CPEParseDlg::AddSection(TCHAR* szSectionName, int nSectionSize)
{
int nSectionNum = m_pNtHeaders->FileHeader.NumberOfSections;
DWORD dwFileAlignment = m_pNtHeaders->OptionalHeader.FileAlignment;
DWORD dwSectionAlignment = m_pNtHeaders->OptionalHeader.SectionAlignment; PIMAGE_SECTION_HEADER pTempSection = m_pSectionHeader + nSectionNum; int nLen = WideCharToMultiByte(CP_ACP, , (LPCWSTR)szSectionName, -, NULL, , NULL, NULL);
char *pszSectionNameA = new char[nLen];
WideCharToMultiByte(CP_ACP, , szSectionName, -, pszSectionNameA, nLen * sizeof(char), NULL, NULL);
//拷贝节名
strncpy((char*)(pTempSection->Name), pszSectionNameA, );
delete[] pszSectionNameA;
pszSectionNameA = NULL;
//节的内存大小
pTempSection->Misc.VirtualSize = AlignSize(nSectionSize, dwSectionAlignment);
//节的内存起始位置
pTempSection->VirtualAddress = m_pSectionHeader[nSectionNum - ].VirtualAddress
+ AlignSize(m_pSectionHeader[nSectionNum - ].Misc.VirtualSize, dwSectionAlignment);
//节的文件大小
pTempSection->SizeOfRawData = AlignSize(nSectionSize, dwFileAlignment);
//节的文件起始位置
pTempSection->PointerToRawData = m_pSectionHeader[nSectionNum - ].PointerToRawData
+ AlignSize(m_pSectionHeader[nSectionNum - ].SizeOfRawData, dwFileAlignment);
//修正节数量
m_pNtHeaders->FileHeader.NumberOfSections++;
//修正映像大小
m_pNtHeaders->OptionalHeader.SizeOfImage += pTempSection->Misc.VirtualSize;
//填充内存映射
FlushViewOfFile(m_lpBase, );
//添加节数据
AddSectionData(pTempSection->SizeOfRawData); CString str;
str.Format(_T("%02X"), m_pNtHeaders->FileHeader.NumberOfSections);
((CEdit*)GetDlgItem(IDC_EDIT_SECTIONNUM))->SetWindowText(str);
EnumSections();
} DWORD CPEParseDlg::AlignSize(int nSectionSize, DWORD dwAlignment)
{
int nSize = nSectionSize;
if (nSize % dwAlignment != )
{
nSectionSize = (nSize / dwAlignment + ) * dwAlignment;
} return nSectionSize;
} void CPEParseDlg::AddSectionData(int nSectionSize)
{
PBYTE pByte = NULL;
pByte = (PBYTE)malloc(nSectionSize);
ZeroMemory(pByte, nSectionSize); DWORD dwNum = ;
SetFilePointer(m_hFile, , , FILE_END);
WriteFile(m_hFile, pByte, nSectionSize, &dwNum, NULL);
FlushFileBuffers(m_hFile); free(pByte);
}
下载地址如下:
http://pan.baidu.com/s/1hqBR06S
PE查看器的更多相关文章
- 用Qt写软件系列一:QCacheViewer(浏览器缓存查看器)
介绍 Cache技术广泛应用于计算机行业的软硬件领域.该技术既是人们对新技术探讨的结果,也是对当前软硬件计算能力的一种妥协.在浏览器中使用cache技术,可以大幅度提高web页面的响应速度,降低数据传 ...
- PE解析器的编写(四)——数据目录表的解析
在PE结构中最重要的就是区块表和数据目录表,上节已经说明了如何解析区块表,下面就是数据目录表,在数据目录表中一般只关心导入表,导出表和资源这几个部分,但是资源实在是太复杂了,而且在一般的病毒木马中也不 ...
- Map工具系列-08-map控件查看器
所有cs端工具集成了一个工具面板 -打开(IE) Map工具系列-01-Map代码生成工具说明 Map工具系列-02-数据迁移工具使用说明 Map工具系列-03-代码生成BySQl工具使用说明 Map ...
- wpf 仿QQ图片查看器
参考博客 WPF下的仿QQ图片查看器 wpf图片查看器,支持鼠标滚动缩放拖拽 实现效果 主要参考的WPF下的仿QQ图片查看器,原博主只给出了部分代码. 没有完成的部分 1.右下角缩略图是原图不是缩略图 ...
- Win10系统怎样让打开图片方式为照片查看器
转载自:百度经验 http://jingyan.baidu.com/article/5d368d1ef0cad13f60c057e3.html 1.首先,我们需要使用注册表编辑器来开启Win10系统照 ...
- 发布两款JQ小插件(图片查看器 + 分类选择器),开源
图片查看器,github地址:https://github.com/VaJoy/imgViewer 效果如下: 这款当初大概写了2小时,有点匆忙地赶出来的,使用的接口很简单: $.bindViewer ...
- IIS事件查看器_WebServer事件查看器_帮助查看IIS-Web服务器事件执行日志
IIS服务器是我们常用的Web站点部署工具,而我们有时可能遇到IIS服务器的应用程序池莫名其妙的关闭了,或者是其他未知原因等等,我们这是可以通过微软提供的WebServer(Web服务事件查看器),来 ...
- wpf图片查看器,支持鼠标滚动缩放拖拽
最近项目需要,要用到一个图片查看器,类似于windows自带的图片查看器那样,鼠标滚动可以缩放,可以拖拽图片,于是就写了这个简单的图片查看器. 前台代码: <Window x:Class=&qu ...
- 在Windows 10下启用旧的照片查看器
从Windows 10开始,默认只能通过“照片”来查看图片了,非常不方便!通过将下列文本保存在.reg文件后导入,即可找回Windows XP时代的“照片查看器”. Windows Registry ...
随机推荐
- nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
启动nginx时报这个错 , 要么用root用户启动 , 要么在配置文件nginx.conf中将server下的listen端口改掉 , 因为在linux中端口号小于1024都是需要root权限的
- Java注解处理器--annotation学习四
Java中的注解(Annotation)是一个很神奇的东西,特别现在有很多Android库都是使用注解的方式来实现的.一直想详细了解一下其中的原理.很有幸阅读到一篇详细解释编写注解处理器的文章.本文的 ...
- OOP三个基本特征:封装、继承、多态
面向对象的三个基本特征是:封装.继承.多态. 封装 封装最好理解了.封装是面向对象的特征之一,是对象和类概念的主要特性. 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类 ...
- spring配置定时器的时间设置
时间大小由小到大排列,从秒开始,顺序为 秒,分,时,天,月,年 *为任意 ?为无限制. 具体如下: "0/10 * * * * ?" 每10秒触发 "0 0 12 ...
- 如何将MVC Areas中的某一个页设为起始页
area的默认页: routes.MapRoute( name: "MyArea", url: "{controller}/{action}/{id}", de ...
- 关于在页面总嵌入iframe,ifram中发起请求,服务器端的session为空问题解决
本文抄袭:http://blog.csdn.net/ray_adon/article/details/6960724 在做项目是 是用了iframe,iframe发起ajax请求,服务器端报sessi ...
- Delphi 在线程中如何使用TClientSocket组件并自动检测该组件
在线程中如何使用TClientSocket组件并自动检测该组件的事件?我想在一个线程中动态创建一个TClientSocket组件,并要求该组件能够自动检测Socket事件(例如OnRead.OnErr ...
- [POJ 2443] Set Operation (bitset)
题目链接:http://poj.org/problem?id=2443 题目大意:给你N个集合,每个集合里有若干个数.M个查询,每个查询有a,b两个数.问是否存在一个集合同时包含a,b这两个数.若存在 ...
- DDL(Oracle)
DDL 数据定义 建表 建视图 建其他 drop create table t (a varchar2 (10));可变字符串最大为10 transaction - ...
- cocos2d-lua class 方法解释
lua中没有类的概念,有的只是表(table),而类之间的继承也就是将父类的表连到了一起,派生类中没有找到的属性和方法就通过元表查找父类,在cocos2d-lua中,封装好的class方法,完美的实现 ...