Use la herramienta de desensamblado IDA para ver el contexto del código ensamblador anormal para ayudar en el análisis de las excepciones del software C++

Tabla de contenido

1. Información general

2. Cómo usar IDA para abrir y ver el código ensamblador del archivo binario

3. Encuentre la ubicación de la instrucción de ensamblaje que falló en IDA

3.1 Cómo encontrar la instrucción ensambladora que causó la excepción en IDA

3.2 Ejemplos

4. Leer el contexto del código ensamblador requiere un cierto conocimiento básico de ensamblador

5. Finalmente


Resumen de desarrollo de funciones comunes de VC++ (lista de artículos de la columna, bienvenido a suscribirse, actualización continua...) https://blog.csdn.net/chenlycly/article/details/124272585 Tutorial de la serie de solución de problemas de excepciones de software C++ desde la entrada hasta el dominio (artículo de la columna lista, Bienvenido a suscribirse, siga actualizando...) https://blog.csdn.net/chenlycly/article/details/125529931 Herramientas de análisis de software C++ desde la entrada hasta la recopilación de casos de dominio (el artículo de la columna se está actualizando...) https :/ /blog.csdn.net/chenlycly/article/details/131405795 Conceptos básicos y avanzados de C/C++ (artículos de columna, actualizados continuamente...) https://blog.csdn.net/chenlycly/category_11931267.html        en el análisis de C++ Cuando el software falla anormalmente, es posible que deba usar la herramienta IDA para ver el código ensamblador del archivo binario exe o dll para ayudar a localizar el problema. Hoy discutiremos el uso de las herramientas IDA para ver los detalles del código ensamblador.

1. Información general

       Cuando usamos Windbg para abrir el archivo de volcado para analizar la excepción, primero verificaremos la instrucción de ensamblaje bloqueada y el valor en el registro relacionado, luego verificaremos la pila de llamadas de función del subproceso donde se encuentra la excepción y verificaremos las variables locales en la función en la pila de llamadas de función o si es necesario El valor de la variable de miembro de datos en el objeto de clase C++ se usa para ayudar en el análisis.

       Sin embargo, en una pequeña cantidad de escenarios, el análisis anterior finalmente no puede localizar el problema. Es necesario usar IDA para ver el contexto del código ensamblador y combinarlo con el código fuente de C++ para un análisis más detallado. Por ejemplo, en los siguientes dos escenarios, es necesario ver el contexto del código ensamblador para ayudar en el análisis:

1) El número de línea de código C++ en la pila de llamadas de función que se muestra en Windbg no coincide con el código más reciente

       La versión de software en la que se produjo el bloqueo anómalo puede ser de hace varios meses o años. El número de línea que se muestra en Windbg es el código del archivo cpp de hace mucho tiempo. El último código del archivo cpp se ha modificado mucho en comparación con esta versión problemática. por lo tanto, los números de línea no coinciden en absoluto con el último código. En este momento, debe usar IDA para verificar el contexto del código ensamblador del módulo donde ocurrió la excepción y ver qué línea de código la causó. Generalmente, debe compararlo con el código más reciente para ver qué línea de código es en el último código.

2) Hay múltiples llamadas a funciones en la línea de código C++ indicada en Windbg donde ocurre el bloqueo, y es difícil determinar directamente qué llamada a función está causando el problema.

        Hay múltiples llamadas a funciones en la línea de código C++ donde el bloqueo se indica en Windbg (como la combinación de múltiples condiciones en la declaración if), es difícil determinar directamente qué llamada a función es defectuosa, puede verificar el código ensamblador para determinar si es Qué función llama al problema, como la siguiente declaración de juicio de condición if:

if (pContainer->IsVisible() && GetTargetImplPtr()->IsReady() && pDataProcImpl->IsBuildFinish)
{
    // 代码省略
}

       Para obtener una explicación teórica detallada del uso de IDA para ver el código ensamblador para ayudar en la resolución de problemas de excepciones de software C++, consulte un artículo escrito anteriormente: Use IDA para ver el
contexto del código ensamblador para ayudar en la resolución de problemas de excepciones de software C++ https://blog.csdn. net/chenlycly /article/details/128942626 https://blog.csdn.net/chenlycly/article/details/128942626

2. Cómo usar IDA para abrir y ver el código ensamblador del archivo binario

       Una vez completada la instalación de IDA, haga doble clic para iniciar el programa y aparecerá el siguiente cuadro emergente:

Haga clic en "Nuevo" para crear un nuevo objeto. Luego aparece para elegir el archivo para abrir:

Puede encontrar la ruta del archivo de destino, simplemente abra el archivo de destino. También puede hacer clic en Cancelar y arrastrar el archivo directamente a IDA. Al abrir un archivo, se le pedirá que elija cómo cargar el archivo:

Para los archivos de números binarios de la versión de Windows, se utiliza el formato de archivo PE y se puede seleccionar el método PE predeterminado.

       A continuación, aparecerá un cuadro de aviso para cargar el archivo pdb:

Elija Sí. Cabe señalar aquí que debemos colocar el archivo pdb en el directorio del mismo nivel que el archivo binario de destino de antemano, de modo que IDA busque el archivo pdb correspondiente y cargue el archivo pdb al abrir el archivo binario. Con los símbolos en el archivo pdb, el código ensamblador abierto por IDA mostrará el nombre de la función específica y la identificación de la variable, así como una gran cantidad de información de comentarios.

       Después de abrir el archivo binario, el modo de vista de gráfico predeterminado (que muestra la relación entre cada módulo de código) es el siguiente:

Debe hacer clic con el botón derecho y hacer clic en el modo de vista Vista de texto en el menú contextual emergente para cambiar al modo de código fuente de ensamblado.

       Podemos saltar a la función especificada, hacer clic en Jump-->Jump o function en la barra de menú:

Aparecerá una lista que contiene todas las funciones del módulo actual, haga clic en el botón Buscar en la parte inferior de la ventana:

Ingrese directamente el nombre de la función de destino que desea ver y, después de buscar la función de destino, haga doble clic en la entrada para saltar al código ensamblador de la función de destino:

También puede presionar la tecla de método abreviado g para saltar directamente a la línea de código de ensamblaje en la dirección especificada:

3. Encuentre la ubicación de la instrucción de ensamblaje que falló en IDA

       En Windbg, puede ver la instrucción de ensamblaje donde ocurrió la excepción y el módulo donde se encuentra esta instrucción de ensamblaje y luego encontrar el archivo binario correspondiente al módulo, abrir el archivo binario con IDA y puede ver el código de ensamblaje de el módulo.

3.1 Cómo encontrar la instrucción ensambladora que causó la excepción en IDA

       En Windbg, puede ver la dirección de la instrucción de ensamblaje anómala (dirección del segmento de código). A través de la dirección de esta instrucción, puede encontrar la ubicación correspondiente en el código de ensamblaje abierto por IDA y luego verificar el contexto de la instrucción de ensamblaje en esta ubicación y compararla con el código fuente de C++, podemos analizar más a fondo el problema.

       La dirección de la instrucción de ensamblaje anómala que se muestra en Windbg es la dirección real después de que se ejecuta el programa principal, que es diferente de la dirección predeterminada estática que se muestra en IDA. Cuando se inicia el programa principal, primero cargará los módulos dll de los que depende en el espacio de proceso y asignará direcciones de segmento de código a cada módulo, de modo que las instrucciones de ensamblaje en cada módulo tengan las direcciones de segmento de código reales en tiempo de ejecución.
Este lugar debe distinguir entre la dirección del segmento de código y la dirección del segmento de datos:

La memoria de la variable definida en el código se asigna en la memoria del segmento de datos, y la dirección de memoria de la variable es la dirección del segmento de datos. La dirección de la instrucción de código binario (código ensamblador) es la dirección del segmento de código.

       Aunque la dirección de ejecución real de la instrucción de ensamblaje anómala es diferente de la dirección predeterminada estática que se muestra en IDA, la ubicación de la instrucción de ensamblaje en relación con el módulo es fija, es decir, el desplazamiento de la dirección de la instrucción de ensamblaje en relación con el módulo siempre es fijado. Puede calcular el desplazamiento de la instrucción de ensamblaje donde ocurrió la excepción en relación con el módulo en Windbg y luego agregar este desplazamiento a la dirección de inicio predeterminada del módulo que se muestra en IDA para obtener la dirección de la instrucción de ensamblaje en IDA. esta dirección, y puede ver la instrucción de ensamblaje que falló.

3.2 Ejemplos

       Usemos un ejemplo específico para explicar cómo encontrar la instrucción ensambladora anormal en el código ensamblador del módulo abierto por IDA. Deliberadamente escribí un código de prueba que lanzaría una excepción de la siguiente manera:

SHELLEXECUTEINFO* pInfo = NULL;

CString strTip;
strTip.Format(_T("cbSize: %d"), pInfo->cbSize );

::MessageBox( NULL, strTip, _T("提示"), MB_OK);

Una variable de puntero de estructura pInfo se define en el código, se inicializa en NULL, y luego no se asigna una dirección de estructura válida al puntero, y este puntero nulo se usa directamente para acceder al miembro cbSize en la estructura, por lo que se accede a una dirección Small cantidad de memoria, por lo que se activa una violación de acceso a la memoria.

       Cuando el programa ejecuta el código anterior, se bloqueará y generará un archivo de volcado. Abra el archivo de volcado con Windbg y configure la ruta del archivo pdb del programa en Windbg.Después de abrir, puede ver la instrucción de ensamblaje que falló anormalmente y los valores en cada registro en ese momento, y ver el código anormal y anormal tipo De la siguiente manera:

En primer lugar, como se puede ver en la figura anterior, lo que sucedió fue una excepción de violación de acceso a la memoria. Luego vea la instrucción de ensamblaje mov ecx,dword ptr [eax] donde ocurrió la excepción (la dirección de la instrucción es 0x00eb3787), y esta instrucción se encuentra en la función CTestDlgDlg::OnBnClickedButton1 del módulo TestDlg.

       A continuación, demostremos cómo encontrar la ubicación de la instrucción de ensamblado donde ocurrió la excepción en IDA. La instrucción de ensamblaje anómala se encuentra en el módulo TestDlg, así que use IDA para abrir el archivo binario TestDlg.exe y ver el código de ensamblaje de este módulo. Primero calculamos el desplazamiento de la instrucción de ensamblaje anormal en relación con el módulo donde se encuentra. La dirección de la instrucción de ensamblaje anormal es 0x00eb3787, use el comando lm para ver la dirección de inicio (dirección del segmento de código) del módulo TestDlg donde se encuentra, de la siguiente manera:

La dirección de inicio del módulo TestDlg es 0x00ea0000, por lo que el desplazamiento de la instrucción de ensamblaje donde ocurre la excepción relativa a la dirección de inicio del módulo TestDlg es:

0x00eb3787 - 0x00ea0000

Luego vamos a IDA, arrastramos el mouse a la parte superior del código ensamblador y vemos la dirección de inicio predeterminada estática del módulo TestDlg que muestra IDA, de la siguiente manera:

La dirección de inicio predeterminada estática del módulo TestDlg es 0x400000, y las direcciones de todas las instrucciones de ensamblaje en este módulo se expanden en función de este valor base. Por lo tanto, la dirección de la instrucción de ensamblaje donde ocurrió la excepción se muestra en IDA:

0x00eb3787 - 0x00ea0000 + 0x00400000 = 0x00413787

Luego presione la tecla de acceso directo g, ingrese 413787 en el cuadro de búsqueda emergente, haga clic en Aceptar y vaya a la ubicación de la instrucción de ensamblaje donde ocurrió la excepción, de la siguiente manera:

De esta forma, podemos ver el contexto de la instrucción de ensamblaje anómala y combinar los comentarios en IDA y el código fuente de C++ para analizar más a fondo el problema.

4. Leer el contexto del código ensamblador requiere un cierto conocimiento básico de ensamblador

       Para leer el contexto del código ensamblador, es necesario dominar ciertos conocimientos básicos de ensamblador, como comprender el propósito de algunos registros comunes, familiarizarse con algunas instrucciones ensambladoras de uso común, comprender la distribución de la pila de llamadas a funciones y comprender el código ensamblador. implementación de llamadas a funciones virtuales C++ (direccionamiento secundario al llamar a una función virtual), etc. Aquí hay una breve mención del propósito de los registros de uso común:

En la instrucción de ensamblaje X86, EAX se usa principalmente para almacenar el valor de retorno de la llamada de función; el registro ECX se usa para transferir la dirección del objeto C++ cuando se llama a la función miembro de C++; ESI es el registro de dirección de origen y EDI es el destino registro de direcciones, utilizado principalmente para la memoria En las instrucciones de operación de cadenas copiadas, como la implementación de ensamblaje de memcpy.

       Con respecto a los conocimientos básicos de ensamblaje que deben dominarse para analizar las excepciones del software C++, no entraré en detalles aquí. Puede consultar mis artículos anteriores:

Resumen de los conocimientos de ensamblado necesarios para analizar las excepciones de software de C++

5. Finalmente

       Es relativamente difícil leer el código ensamblador directamente, a menos que tenga un conocimiento sólido del lenguaje ensamblador y capacidad de desensamblado. En el trabajo real, generalmente leemos el código ensamblador contra el código C++ y, al mismo tiempo, combinamos los comentarios en el contexto del código ensamblador para ayudar en la visualización, que es mucho más fácil que simplemente leer el código ensamblador directamente. Además, el compilador optimizará mucho el código en Release, y es difícil tener una correspondencia uno a uno entre el código C++ optimizado y el código ensamblador optimizado, lo que requiere atención.

       Cuando analizamos las excepciones del software C++, simplemente usamos la herramienta IDA para abrir el archivo binario exe o dll con IDA para ver el código ensamblador en el archivo (IDA desensamblará el código de máquina binario en el archivo binario en código ensamblador), para ayudar analizar problema. Este artículo no describe en detalle las funciones de la herramienta IDA. Los amigos interesados ​​pueden leer el libro clásico de IDA "Guía definitiva de IDA Pro".

Código de máquina binario, el código de ensamblaje es equivalente al código de máquina binario, el código de ensamblaje es un mnemotécnico del código de máquina binario y el código de ensamblaje es muy legible. Lo que se ejecuta en la CPU es código de máquina binario, que es equivalente a la ejecución de código ensamblador.Al ver el código ensamblador, puede ver los detalles específicos de ejecución del programa.

Supongo que te gusta

Origin blog.csdn.net/chenlycly/article/details/132158574#comments_28048319
Recomendado
Clasificación